提问人:jagadesh 提问时间:12/28/2022 更新时间:12/30/2022 访问量:399
Java 浮点数乘法给出错误的结果
Java Float multiplication giving wrong result
问:
使用 FLOAT 进行乘法会产生明显的差异。
public static void main(String[] args) {
// using string and parsing instead of actual data type is part of use case, that is why representing the same here
double v1 = parseDouble("590.0");
double v2 = parseDouble("490.0");
double v3 = parseDouble("391.0");
float v4 = parseFloat("590.0");
float v5 = parseFloat("490.0");
float v6 = parseFloat("391.0");
System.out.println(new BigDecimal(v1 * v2 * v3));
System.out.println(new BigDecimal(v4 * v5 * v6));
System.out.println(BigDecimal.valueOf(Float.parseFloat("289100.0") * Float.parseFloat("391.0")));
System.out.println(BigDecimal.valueOf(Double.parseDouble("289100.0") * Double.parseDouble("391.0")));
}
输出:
113038100 // double multiplication
113038096 // float multiplication
113038096
113038100
对于上面的代码,
(590.0 * 490.0 * 391.0) 给出 113038100 使用 double
(590.0 * 490.0 * 391.0) 给出113038096使用浮点数 (113038100 - 113038096 = 4 // 差值)
我已经通读了此链接 https://floating-point-gui.de/basic/ 并且能够理解浮点计算是如何发生的,但是所有 4 个计数都不同是出乎意料的。
请帮助我理解以下事项
- 这是正确的吗 首先
- 总是浮点给出错误的数字吗?
- 正如我所看到的,double 也使用相同的技术,所以如果我们使用 double 来保证我们得到正确的结果
答:
总是浮点给出错误的数字吗?
这取决于数字,如果数字可以使用浮点精度表示,那就没问题了
“正如我所看到的,double也使用相同的技术,所以我们有多少保证 如果我们使用double,则必须得到正确的结果”
double 也有同样的问题,但由于 double 具有更高的精度,因此可能性会降低,但它仍然会发生
因此,当您需要非常精确的结果(例如在科学或金融应用程序中)时,您将需要使用 BigDecimal
观看此视频,它解释了浮点数的工作原理 https://www.youtube.com/watch?v=ajaHQ9S4uTA
评论
这是正确的吗 首先
Java 格式为 IEEE-754 binary32。在这种格式中,每个有限数都表示为一个符号、一个 24 位整数和一个从 2−149 到 2104 的 2 次幂缩放。整数部分称为有效部分。(该格式通常被描述为符号,一个 24 位数字,第一位后有一个二进制点,因此它的值为 [0, 2),缩放范围为 2−126 到 2127。这些格式在数学上是等效的,此处使用的格式在 IEEE-754 标准中注明为一个选项。在正常形式中,24 位整数为 223 或更大。(小于 2−126 的可表示数字不能以正常形式表示,并且必然是次正态的。float
在这种格式中,590 可以表示为 +590•20 或 +8,339,456•2−14。490 是 +490•20 或 +16,056,320•2−15。
它们的乘积是 +289,100•20 或 +9,251,200•2−5。
391 是 +391•20 或 +12,812,288−15。
+289,100•2 0 和 +391•20 的普通算术乘积为 +113,038,100•20。但是,113,038,100 不是 24 位数字;它是一个 27 位数字。为了使其低于 224,我们可以调整缩放比例,将有效数乘以 1/8,然后将缩放比例乘以 8 = 23。
这给了我们 +14,129,762.5•23.但是,现在有效数不是整数。此结果无法以格式表示。为了产生结果,定义了格式加法的运算,以将普通算术四舍五入到最接近的可表示值。在这种情况下,存在平局,我们可以向上或向下舍入 .5。平局通过四舍五入来解决,使低位数均匀,因此我们四舍五入到 +14,129,762•23.float
float
+14,129,762•23 是 113,038,096。这就是你得到的结果,所以它是正确的。
总是浮点给出错误的数字吗?
这没有错;计算机按照其规范运行。
Observe 是 32 位格式,但实数是无限多的。甚至还有无限多的有理数。32 位格式不可能产生与理论实数算术或有理数算术相同的结果。可能的结果比可表示的值多。float
64 位格式也是如此。整数格式、固定精度格式以及具有固定位数的所有数字格式也是如此。固定位数的位数不能表示无限多的值。double
您的评论表明您认为浮点数会为小数值(小于 1 的数字)生成近似结果。但是,可以表示多少个值的限制适用于所有比例。在每个刻度(每个 2 的幂)下,只有 224 个值是可表示的(正常形式为 223)。对于尺度 20,所有低于 224 的非负整数都是可表示的。但是,在此之上,只有一些整数是可表示的。首先,我们必须跳过每两个整数,然后是每四个,然后是每八个,依此类推。
浮点运算旨在近似于实数算术。当您想要近似实数算术时,应该使用它。除极少数例外情况外,当您需要精确算术时,不应使用它。
评论
float
12345678901234567890
123
(590.0 * 490.0 * 391.0)
1.130381 * 10⁸
1.130381E8