Rust的f64
类型提供函数round()
,它舍入到最接近的整数,但返回f64
。另一方面,Java的Math.round(double)
返回long
。我可以拨打round()
然后转发给i64
,但是这会保证我得到正确的结果吗?在这里,“正确”表示获得最接近的i64
- Java的round()
返回“最近的长”。
答案 0 :(得分:8)
从the book开始,从浮点到整数类型的转换向零舍入,因此首先舍入几乎正确:f.round() as i64
。
但是,如果f64
超出范围(巨大幅度)i64
,它目前也是未定义的行为(但这是a bug)。因此,您应该首先钳制该值(或者可能更好,引发错误或断言)。可能显而易见的答案并不奏效:
f.max(std::i64::MIN as f64).min(std::i64::MAX as f64).round() as i64
因为i64::MAX
到f64
的转换并不准确,将上述应用到1e100
会产生很大的负值(在我的测试中;如上所述& #39; s实际上是未定义的。)
如果浮点值超出了应用程序期望的合理范围,那么最好的选择似乎是返回一些错误。
答案 1 :(得分:7)
您可以使用conv
包装箱:
use conv::prelude::*;
let x = 9_223_371_487_098_961_920i64 as f64;
println!("{:?}", x.approx_as_by::<i64, RoundToNearest>());
// Ok(9223371487098962944)
let x = 9_223_372_036_854_775_807i64 as f64;
println!("{:?}", x.approx_as_by::<i64, RoundToNearest>());
// Err(FloatError::PosOverflow(..))
答案 2 :(得分:1)
这是一个简单的&#34;信封背面&#34;实现:
const INTEGRAL_LIMIT: f64 = 9007199254740992.0;
#[derive(Debug, PartialEq, Eq)]
enum Error {
NaN,
Overflow,
Underflow,
}
fn try_from(f: f64) -> Result<i64, Error> {
let f = f.round();
if f.is_nan() { return Err(Error::NaN); }
if f < -INTEGRAL_LIMIT { return Err(Error::Underflow); }
if f > INTEGRAL_LIMIT { return Err(Error::Overflow); }
Ok(f as i64)
}
它带有一个最小的测试套件,通过:
fn main() {
assert_eq!(try_from(std::f64::NAN), Err(Error::NaN));
assert_eq!(try_from(std::f64::NEG_INFINITY), Err(Error::Underflow));
assert_eq!(try_from(-9007199254740994.0), Err(Error::Underflow));
assert_eq!(try_from( 9007199254740994.0), Err(Error::Overflow));
assert_eq!(try_from(std::f64::INFINITY), Err(Error::Overflow));
assert_eq!(try_from(-INTEGRAL_LIMIT), Ok(-9007199254740992));
assert_eq!(try_from( INTEGRAL_LIMIT), Ok( 9007199254740992));
}
我实际上期待TryFrom
实现可用,但没有找到。