【问题标题】:Why Java's Math.round() cannot handle this number?为什么 Java 的 Math.round() 不能处理这个数字?
【发布时间】:2016-05-17 03:14:01
【问题描述】:

我有这样的代码:

System.out.println("Math.round(1423562400L) => " + Math.round(1423562400L));

结果是这样的:

Math.round(1423562400L) => 1423562368

这个值是一个 64 位整数,但它很容易放入一个应该适合双精度的 32 位整数中。怎么回事?

【问题讨论】:

标签: java rounding


【解决方案1】:

根据JLS

15.12.2.5。选择最具体的方法

如果多个成员方法既可访问又适用于方法调用,则有必要选择一个为运行时方法分派提供描述符。 Java 编程语言使用选择最具体方法的规则。

非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法而不会出现编译时类型错误,那么一个方法比另一个方法更具体。

由此可见Math.round(float)Math.round(double)更具体,由于都是valid overloads,编译器选择前者,导致数据丢失。

要更正您的输出,只需将 1423562400L 更改为 1423562400d

【讨论】:

  • 您能否详细说明为什么float 版本比double 版本更具体?因此,它首先尝试浮点版本,如果它编译然后它使用它。但是为什么要先浮动版本。这在 JLS 中没有指定。
  • @swdev 阅读我引用的第二段。这意味着浮点版本更具体,因为浮点可以作为双精度传递,但反之则不行(没有缩小转换)。
  • 谢谢,这就解释了。与 C++ 相比,这是一种奇怪的行为。在该语言中,您将获得以下error: call of overloaded 'round(long int)' is ambiguous 将整数传递给定义了两种浮点类型的函数。
  • @swdev:是的,这里可能是模棱两可的重载错误更安全的选择。但是那艘船已经航行了。
  • @swdev 选择更具体的重载的概念对我个人来说很有意义。更令人惊讶的是,做多浮动被认为是一种扩大的转换。但正如我在链接的答案中所讨论的那样,从技术上讲,您可以就 long to double 提出相同的论点。
【解决方案2】:

我认为Math.round() 没有支持long 参数的实现。这是Math.round() 签名。

Math.round(double a);
Math.round(float a);

Math.round() 接受doublefloat,因此当您传递long 时,您正在执行类似(long 隐式转换为浮动)

float x = 1423562400L;
System.out.println(Math.round(x));

要解决此问题,您可以先将 long 值添加到 double,它会像魅力一样工作。

double x = 1423562400L;
System.out.println(Math.round(x));

为了简化你可以这样做

Math.round((double)1423562400L)

Math.round(1423562400d)

下图显示了隐式转换的工作原理以及为什么long会被转换为float

图片来源here

【讨论】:

  • 请勿在此处张贴文字图片。贴出文字。这是浪费你的时间,我不关心,我们的带宽,我关心。它还可以防止复制/粘贴到 cmets。基本上没有意义。
  • long converts to float implicitly。是的,但 long 也隐式转换为 double (在这种情况下没有损失)。但这里选择了“更窄”的重载。
  • 转换发生时。遵循层次结构。所以第一个 long 将被转换为 float,因为我们有一个支持 float 的 round()。
【解决方案3】:

注意 Math.round 的签名是

public static int round(float a)

它接受一个 32 位浮点数,现在你给这个方法加上一个 64 位长, 它将 long 转换为 int,然后将其转换为 float。

System.out.println(Math.round((int)1423562400L));
System.out.println(Math.round((float)1423562400L));

代码也打印 1423562368

如果你把它显式地转换成双精度 那么结果是正确的

1423562400

【讨论】:

  • 嗯,同样的方法还有一个double重载。人们本可以希望使用那个来代替。
  • @Thilo,是的,这也是我的希望。
猜你喜欢
  • 1970-01-01
  • 2011-09-24
  • 2017-04-04
  • 2020-05-06
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
  • 2013-05-15
相关资源
最近更新 更多