1/3+1/6=计算机是如何得出0.5的?
两个无限循环小数相加,运算器是如何处理的?
首先,虽然1/3和1/6都是无限循环小数,但在CPU里,位数都是有限的,参见:浮点数_百度百科,英语好的可以看Single-precision floating-point format
所以实际上1/3和1/6在内存里不是长度无限的,具体来说,以gcc 481作为测试环境的话,大概是这样的:
1/3在内存里是0x3eaaaaab
1/6在内存里是0x3E2AAAAB
这两个数字如果换算成十进制小数,那么应该是:
1/3 => 0.3333333432674407958984375
1/6 => 0.16666667163372039794921875
也就是说,这两个数本身在内存就是不精确的。
因为计算机内部都是二进制的,这两个数值用二进制表示是这样的:
1/3 => 0.01010101010101010101011
1/6 => 0.001010101010101010101011
现在计算机做浮点都是硬浮点,那么具体的计算过程都是由CPU来完成的。
1/3+1/6 = 0.01010101010101010101011 + 0.001010101010101010101011
具体过程:
0.010101010101010101010110
+ 0.001010101010101010101011
--------------------------------
0.100000000000000000000001
因为这个时候精度已经多出一位了,此时CPU要做一个取舍,根据Intel的手册(参见这里浮点处理和指令编码(更新完毕))
(注:实际CPU未必是这种位对齐的算法,具体要看硬件实现)
这种情况下,最后的位数是01默认是舍掉的。
所以最终的结果就是0.10000000000000000000000,这个数字正好就是十进制的0.5
具体二进制十进制转换过程可以参考一下:十进制转二进制
参考代码:
#include
#include
int main()
{
float x = 1.0/3, y = 1.0/6;
unsigned int a, b;
memcpy(&a, &x, sizeof(a));
memcpy(&b, &y, sizeof(b));
printf("%.100f %.100f %.100f\n", x, y, x + y);
printf("%x %x\n", a, b);
return 0;
}