参见英文答案 >
Why printf round floating point numbers?3个
看看这段代码.
10/3返回3.3333332538604736328125000并且当我在calcutor中乘以3时得到9.99,但是如果通过代码执行相同的操作我得到10.00.
怎么可能?
看看这段代码.
10/3返回3.3333332538604736328125000并且当我在calcutor中乘以3时得到9.99,但是如果通过代码执行相同的操作我得到10.00.
怎么可能?
#include <stdlib.h> #include <stdio.h> int main() { float v = 10.f/3.f; float test = v*3.f; printf("10/3 => %25.25f \n (10/3)*3 => %25.25f\n",v,test); return 0; }
这是没有printf的汇编代码,使用默认的gcc 7.2.1参数编译:
0000000000400497 <main>: 400497: 55 push rbp 400498: 48 89 e5 mov rbp,rsp 40049b: f3 0f 10 05 b1 00 00 movss xmm0,DWORD PTR [rip+0xb1] # 400554 <_IO_stdin_used+0x4> 4004a2: 00 4004a3: f3 0f 11 45 fc movss DWORD PTR [rbp-0x4],xmm0 4004a8: f3 0f 10 4d fc movss xmm1,DWORD PTR [rbp-0x4] 4004ad: f3 0f 10 05 a3 00 00 movss xmm0,DWORD PTR [rip+0xa3] # 400558 <_IO_stdin_used+0x8> 4004b4: 00 4004b5: f3 0f 59 c1 mulss xmm0,xmm1 4004b9: f3 0f 11 45 f8 movss DWORD PTR [rbp-0x8],xmm0 4004be: b8 00 00 00 00 mov eax,0x0 4004c3: 5d pop rbp 4004c4: c3 ret 4004c5: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0] 4004cc: 00 00 00 4004cf: 90 nop
注意,GNU BC程序中的10/3返回3.3333333333333333333333(* 3 => 9.9999),并且在SciLab中返回3.3333333333333334813631(* 3 => 10).
解决方法
你最终得到的结果恰好是10,因为表示恰好是这样的.我对float和double的实现都是一样的.
让我们看一个使用double的例子:
如果我们打印出10./3.在使用%a的十六进制浮点表示法中,我们得到:
0x1.aaaaaaaaaaaabp+1
这与IEEE754双重表示0x401aaaaaaaaaaa匹配.
以上数字归一化为:
0x3.5555555555558
二进制:
11.0101010101010101010101010101010101010101010101011
为了简单起见,让我们添加三次而不是乘以3:
11.0101010101010101010101010101010101010101010101011 + 11.0101010101010101010101010101010101010101010101011 --------------------------------------------------------- 110.1010101010101010101010101010101010101010101010111 + 11.0101010101010101010101010101010101010101010101011 --------------------------------------------------------- 1010.0000000000000000000000000000000000000000000000000
这正好是10.
编辑:
看起来我设法在最后几位数字处理数学.实际总和:
11.0101010101010101010101010101010101010101010101011 + 11.0101010101010101010101010101010101010101010101011 --------------------------------------------------------- 110.1010101010101010101010101010101010101010101010110 + 11.0101010101010101010101010101010101010101010101011 --------------------------------------------------------- 1010.0000000000000000000000000000000000000000000000001
所以它不完全是10,而是最不重要的一点.
我注意到使用float时有类似的区别.
10.f / 3.f用%a打印:
0x1.aaaaaap+1
标准化:
0x3.555554
二进制:
11.0101010101010101010101
然后我们添加:
11.0101010101010101010101 + 11.0101010101010101010101 ------------------------------ 110.1010101010101010101010 + 11.0101010101010101010101 ------------------------------ 1001.1111111111111111111111
再次,由最不重要的位.
至于实际结果如何四舍五入,我不能说.