gpt4 book ai didi

java - 为什么有些 double 除法在java操作中是正确的?

转载 作者:行者123 更新时间:2023-12-05 05:48:04 25 4
gpt4 key购买 nike

我理解二进制数的理论,所以double数的运算并不精确。但是,在 Java 中,我不知道为什么“(double)65/100”是 0.65,这在十进制数中是完全正确的,除了 0.6500000000004

double a = 5;
double b = 4.35;
int c = 65;
int d = 100;
System.out.println(a - b); // 0.6500000000000004
System.out.println((double) c / d); // 0.65

最佳答案

Java 完全搞砸了 有它自己的处理浮点二进制到十进制转换的方法。

一个简单的 C 程序(使用 gcc 编译)给出了结果:

printf("1: %.20f\n", 5.0 - 4.35);         // 0.65000000000000035527
printf("2: %.20f\n", 65./100); // 0.65000000000000002220

虽然 Java 给出了结果(注意你只需要 17 位数字就可以看到它,但我试图让它更清楚):

System.out.printf("%.20f\n", 5.0 - 4.35); // 0.65000000000000040000
System.out.printf("%.20f\n", 65./100); // 0.65000000000000000000

但是当使用 %a 格式说明符时,两种语言 printf 底层十六进制(正确)值:0x1.4ccccccccccd00000000p-1

因此,Java 在代码中的某个位置执行了一些非法舍入。 这里明显的问题是 Java 有一组不同的规则来将二进制转换为十进制,与 Java specification 不同。 :

The number of digits in the result for the fractional part of m or a is equal to the precision. If the precision is not specified then the default value is 6. If the precision is less than the number of digits which would appear after the decimal point in the string returned by Float.toString(float) or Double.toString(double) respectively, then the value will be rounded using the round half up algorithm. Otherwise, zeros may be appended to reach the precision. For a canonical representation of the value, use Float.toString(float) or Double.toString(double) as appropriate. (emphasis mine)

并且在toString specification :

How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0. (emphasis mine)

因此,Java 确实执行了与 C 不同的二进制到十进制的转换,但它仍然比其他任何方法更接近真实的二进制值,因此规范保证二进制值可以通过十进制到二进制的转换恢复回来。

William Kahan 教授在这篇文章中警告了一些 Java 浮点问题:

How Java’s Floating-Point Hurts Everyone Everywhere

但这种转换行为似乎是 IEEE 投诉的。

编辑:我在评论中包含了@MarkDickinson 提供的信息,以报告此 Java 行为(尽管与 C 不同)已记录在案并且符合 IEEE 标准。这个已经解释过了here , here , 和 here .

关于java - 为什么有些 double 除法在java操作中是正确的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70875083/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com