为什么Java的Math.round()无法处理这个数字?

5

我有这样的代码:

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

结果如下:
Math.round(1423562400L) => 1423562368

这个值是一个64位整数,但它可以很容易地放进一个32位整数里面,并且应该适合于double。发生了什么事情?


1
当你首先将其转换为(double)时,它工作正常。显然,否则它是一个float ?! - Thilo
1
但是为什么long会自动转换为float - swdev
@swdev JLS 15.12.2指出,float和double都适用,而JLS 15.12.2.5则说明float是最具体的方法 - Nier
参见:https://dev59.com/6YDba4cB1Zd3GeqPIL11 - Thilo
3个回答

7
根据JLS
选择最具体方法
如果有多个成员方法对方法调用既可访问又适用,则需要选择一个为运行时方法分派提供描述符。 Java编程语言使用的规则是选择最具体的方法。
非正式直觉是,如果第一个方法处理的任何调用可以传递给另一个方法而不会发生编译时类型错误,则一个方法比另一个方法更具体。
由此可知,Math.round(float)Math.round(double)更具体,由于它们都是有效重载, 编译器选择前者,导致数据丢失。
要更正您的输出,请将1423562400L更改为1423562400d

你能详细解释为什么float版本比double版本更具体吗?因此,它首先尝试浮点版本,如果编译成功,则使用它。但是为什么首选浮点版本?这在JLS中没有指定。 - swdev
@swdev 请阅读我引用的第二段。它意味着浮点版本更具体,因为浮点数可以作为双精度传递,但反之不行(除非进行缩小转换)。 - shmosel
谢谢,这解释清楚了。与C++相比,这是一种奇怪的行为。在那种语言中,如果将整数传递给同时定义了浮点类型的函数,你会得到以下错误:error: call of overloaded 'round(long int)' is ambiguous - swdev
@swdev:是的,可能在这里选择模糊重载错误会更安全。但那艘船已经开走了。 - Thilo
@swdev 对我个人来说,选择更具体的重载概念是有意义的。更令人惊讶的是,long到float被认为是一种扩展转换。但正如我链接的答案中所讨论的那样,你可以从技术上同样地对long到double做出同样的论证。 - shmosel

0

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

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

Math.round() 接受 doublefloat,因此当您传递 long 时,您正在执行类似于 (long 隐式转换为 float) 的操作。

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

enter image description here

图片来源 这里


请勿在此处发布文本图片。这是浪费您的时间,我不关心,也是浪费我们的带宽,我很在意。这还会防止将内容复制/粘贴到评论中。这基本上是毫无意义的。 - user207421
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Thilo
当进行转换时,会按照层次结构进行操作。因此,首先将long转换为float,因为我们有一个支持float的round()函数。 - A0__oN

-1
请注意,Math.round的签名是:
public static int round(float a)

它接受一个32位的浮点数,现在你把一个64位的长整型传入了这个方法, 它会将长整型截断为整型,然后转换成浮点数。

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

代码也会打印1423562368

如果你显式地将其转换为double类型,那么结果就是正确的

1423562400


好的,同样的方法也有一个double重载。人们本可以希望使用它。 - Thilo
@Thilo,是的,这也是我的希望。 - swdev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接