Tor*_*sen 1 c# math rounding-error
double a = 135.24; // a is set to 135.24000000000001 actually
double b = Math.Round(a, 0); // set to 135.0
double c = Math.Round(a, 1); // set to 135.19999999999999
double d = Math.Round(a, 2); // set to 135.24000000000001
double e = Math.Round(a, 3); // set to 135.24000000000001
double f = Math.Round(a, 4); // set to 135.24000000000001
double g = Math.Round(a, 5); // set to 135.24000000000001
double h = Math.Round(a, 10); // set to 135.24000000000001
double i = Math.Round(a, 14); // set to 135.24000000000001
double j = Math.Round(a, 2
, MidpointRounding.AwayFromZero ); // set to 135.24000000000001
double k = Math.Round(a, 2
, MidpointRounding.ToEven ); // set to 135.24000000000001
Run Code Online (Sandbox Code Playgroud)
Sooooo,这意味着135.24无法用双精度表示,对吧?
是的,135.24不能用double表示,因为double使用二进制指数表示法.
即:135.24可以以2为基数以指数形式表示为1.0565625*128 =(1 + 1/32 + 1/64 + 1/128 + 1/1024 + ...)*(2**7).
表示不能完全表达,因为13524不会除以5.让我们看看:
135.24 = 13524/(10**2)表示是有限的
<=>存在整个x和n满足135.24 = x/(2**n)Run Code Online (Sandbox Code Playgroud)135.24 = x/(2**n) 13524 / (10**2) = x / (2**n) 13524 * (2**n) = (10**2) * x 13524 * (2**n) = 2*2*5*5 * x左侧没有"5",所以无法完成(称为算术的基本定理)
通常,只有在十进制数的素数因子分解中有足够数量的"五"时,有限二进制表示才是精确的.
现在有趣的部分:
double delta = 0.5;
while( 1 + delta > 1 )
delta /= 2;
Console.WriteLine( delta );
Run Code Online (Sandbox Code Playgroud)
双精度在1附近不同,在0附近不同,对于一些大数字不同.维基百科上的一些二进制表示示例:双精度浮点格式
但最重要的是,内部处理器浮点栈可以有很多更好的精度超过8个字节(双).如果数字不必传输到RAM并且被剥离到8个字节,我们可以获得非常好的精度.
在不同的处理器(AMD,Intel),语言(C,C++,C#,Java)或编译器优化级别上测试类似的东西可以得到大约1e-16,1e-20甚至1e-320的结果
看一下CIL /汇编程序/ jasmin代码,看看究竟发生了什么(例如:对于C++ g++ -S test.cpp创建test.s带有汇编程序代码的文件)