在以下程序中,您可以看到每个值略小于.5向下舍入,除了0.5.
for (int i = 10; i >= 0; i--) {
long l = Double.doubleToLongBits(i + 0.5);
double x;
do {
x = Double.longBitsToDouble(l);
System.out.println(x + " rounded is " + Math.round(x));
l--;
} while (Math.round(x) > i);
}
Run Code Online (Sandbox Code Playgroud)
版画
10.5 rounded is 11
10.499999999999998 rounded is 10
9.5 rounded is 10
9.499999999999998 rounded is 9
8.5 rounded is 9
8.499999999999998 rounded is 8
7.5 rounded is 8
7.499999999999999 rounded is 7
6.5 rounded is 7 …Run Code Online (Sandbox Code Playgroud) 在没有SSE2的情况下,针对没有SSE2的英特尔处理器的Java运行时strictfp是如何处理浮点非正规的?
即使将387 FPU设置为53位精度,它仍保持超大的指数范围:
策略包括重新计算导致模拟浮点的非正规值的操作,或沿着这种技术的线路的永久指数偏移,为OCaml配备63位浮点数,从指数借用一点以避免双重-四舍五入.
在任何情况下,除非可以静态地确定操作不下溢/溢出,否则我认为没有办法避免每个浮点计算至少有一个条件分支.如何处理异常(溢出/下溢)情况是我的问题的一部分,但这不能与表示的问题分开(永久指数偏移策略似乎意味着只需要检查溢出).
假设严格的IEEE 754(没有多余的精度)和舍入到最接近的偶数模式,3*x+x总是== 4*x(因此确切没有溢出),为什么?
我无法展示一个反例,所以我对每一个可能的尾部位模式abc和圆形情况进行了长时间的讨论,但我觉得我可能错过了一个案例,也错过了一个简单的演示......
我也有一种直觉,可以将其扩展到(2^n-1) x + x == 2^n x并且在这种情况下测试尾随位的每个组合都不是一种选择.
(2^n - 1) x == 2^n x - x只要n <= 54,我们应该具有IEEE 754的属性,但y-x+x == y通常不是真的......
只要使用浮点数,0.1就不能在内存中精确表示,所以我们知道这个值通常是0.10000000000000004.
但是当使用go时加0.1和0.2.我得到0.3.
fmt.Println(0.1 + 0.2)
// Output : 0.3
Run Code Online (Sandbox Code Playgroud)
为什么0.3出来而不是0.30000000000000004?
以下表达式返回false(例如,在Java和C#中)
0.1 + 0.1 + 0.1 == 0.3
Run Code Online (Sandbox Code Playgroud)
所以我们了解到我们总是像这样比较双打和浮点数
Math.abs(double1 - double2) < epsilon
Run Code Online (Sandbox Code Playgroud)
但为什么呢
0.1 + 0.1 == 0.2 returns true and
0.1 + 0.1 + 0.1 == 0.3 returns false?
Run Code Online (Sandbox Code Playgroud)
我知道这与尾数有关,但我并不完全理解.
遵循Go代码
for i := 0.0 ; i < 5 ; i+=0.1 {
fmt.Printf("%v, ", i)
}
导致此(部分)输出
0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5
Run Code Online (Sandbox Code Playgroud)
为什么我得到0.30000000000000004而不是0.3?