我理解二进制数的理论,所以双精度数的运算是不精确的。但是,在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
爪哇岛
完全搞砸了
有自己处理浮点二进制到十进制转换的方法。
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.4cccccccccd000000p-1
。
<罢工> 因此,Java在代码中的某个位置执行了一些非法舍入。 这里明显的问题是,Java有一套不同的规则来将二进制转换为十进制,从Java规范:
m或a的小数部分的结果中的位数等于精度。如果未指定精度,则默认值为6。如果精度小于Float.toString(float)或Double.toString(double)分别返回的字符串中小数点后出现的位数,则将使用round half up算法对值进行舍入。否则,可能会附加零以达到精度。对于该值的规范表示形式,请根据需要使用Float.toString(float)或Double.toString(double)。(强调我的)
在toString
规范中:
m或a的小数部分必须打印多少位数?必须至少有一位数字来表示小数部分,除此之外,还必须有尽可能多的数字来唯一区分参数值和相邻的double类型值。即假设x是用这种方法对一个有限的非零自变量d产生的十进制表示所表示的精确的数学值,那么d一定是最接近x的double值;或者,如果两个double值同样接近x,则d必须是其中之一,并且d的有效数位的最低有效位必须是0。(强调我的)
因此,Java确实执行了不同于C的二进制到十进制转换,但它比任何其他值都更接近真实的二进制值,因此规范保证二进制值可以通过十进制到二进制的转换恢复。
William Kahan教授在本文中警告了一些Java浮点问题:
Java的浮点运算是如何伤害所有人的
但这种转换行为似乎是IEEE的抱怨。
编辑:我在评论中包含了@MarkDickinson提供的信息,以报告这种Java行为,尽管不同于C,但已记录在案,并且符合IEEE。这已经在这里、这里和这里进行了解释。
什么是“精度”?使用float和double时,单和双有什么区别?“单精度32位IEEE 754浮点”“双精度64位IEEE 754浮点”是什么意思?
IEEE 754浮点数是离散的。 查看此代码在IdeOne上的实时运行。通用域名格式。在JDK8中运行时,输出是 浮点值按预期打印。我预计双倍值0.1d会像1.000000000000000055511151231260一样打印。为什么它在分数部分打印所有零? 如果我把双变量d转换成字符串,它会输出0.1。 java如何将0.1d(大约为1.0000000 149011938476565E-1)的
问题内容: java中双值的乘法运算符的保证精度是多少? 例如,2.2 * 100是220.00000000000003,但是220是双精度数。220.00000000000003是220之后的下一个两倍。 问题答案: 乘法工作正常,但不能精确表示为双精度。最接近的双打是: 2.199999999999999733(0x4001999999999999) 2.200000000000000177(
问题内容: 当我使用双精度数在Java中将317除以219时,得到1。 例如: 输出为:1。 这是因为它是重复的小数吗?不得不使用BigDecimal代替,这很烦人。 问题答案: 试试这个 java中编码数字的默认类型是,因此使用现有的代码,java正在使用两个数字,并且除法的结果也将是,这将截断小数部分以得出最终结果。然后将此结果从转换为,而没有编译器警告,因为它是 扩大的转换 (保证源类型“适
对于实现精确 IEEE 754 算术的 C99 编译器,是否存在型的 、的值,使得 ? 编辑:所谓“实现精确的IEEE754算法”,我指的是一个正确地将FLT_EVAL_METHOD定义为0的编译器。 提供符合IEEE 754标准的浮点数的C编译器只能将单精度除法替换为常数,如果所述逆本身可以完全表示为。 实际上,这种情况只发生在2的幂上。因此,程序员Alex可能确信< code>f / 2.0f
问题内容: 我正在编写一个简单的Java程序。我需要从输入中获取一个字符串并将其分为两部分:1-double 2-string。然后,我需要对double进行简单的计算,并将结果发送到具有特定精度的输出(4)。它工作正常,但是当输入为0时出现问题,则不能正常工作。 例如,对于这些输入,输出将是: 1公斤 输出:2.2046 3.1公斤 输出:6.8343 但是当输入为0时,输出应为0.0000,但