我一直在玩浮点数,基于我过去对它们的了解,0.1 + 0.2
最终变成像0.30000000000000004
这样的事实不要让我感到惊讶。
让我感到惊讶的是,整数算术总是似乎才能正常工作而且没有任何这些工件。
我首先在JavaScript(node.js中的Chrome V8)中注意到了这一点:
0.1 + 0.2 == 0.3 // false, NOT surprising
123456789012 + 18 == 123456789030 // true
22334455667788 + 998877665544 == 23333333333332 // true
1048576 / 1024 == 1024 // true
C ++(Mac OS X上的gcc)似乎具有相同的属性。
净结果似乎只是整数,因为缺少一个更好的词 - 工作。只有当我开始使用十进制数字时,事情变得不稳定。
这是设计的特征,数学工件,还是编译器和运行时环境所做的一些优化?
答案 0 :(得分:4)
这是设计的特征,数学工件,还是编译器和运行时环境所做的一些优化?
这是实数的一个特征。现代代数(现代代数,不是高中代数;数学专业在基本微积分和线性代数类之后在现代代数中取一类)的定理说,对于某些正整数 b ,任何正实数 r 可以表示为 r = a * b p ,其中 a 是在[1, b )和 p 中是一些整数。例如,1024 10 = 1.024 10 * 10 3 。正是这个定理证明了我们使用科学记数法是正确的。
该数字 a 可以被分类为终端(例如1.0),重复(1/3 = 0.333 ......)或非重复(pi的表示)。这里有终端号码的小问题。任何终端号码也可以表示为重复数字。例如,0.999 ...和1是相同的数字。表示中的这种模糊性可以通过指定可以表示为终端数的数字表示为这样来解决。
您发现的是所有整数在任何基数中具有终端表示的结果。
这里有一个关于如何在计算机中表示实数的问题。正如int
和long long int
不代表所有整数一样,float
和double
并不代表所有的实数。在大多数计算机上用来表示实数 r 的方案是以 r = a * 2 p 的形式表示 sup>,但尾数(或有效数) a 被截断为一定数量的位,而指数 p 被限制为某个有限数。这意味着某些整数无法准确表示。例如,即使googol(10 100 )是一个整数,它的浮点表示也不准确。 googol的基数2表示是333位数。这个333位的尾数被截断为52 + 1位。
这导致双精度算术不再精确,即使对于整数,如果所讨论的整数大于2 53 。在2 53 和2 64 之间的值上使用unsigned long long int
类型尝试您的实验。您会发现对于这些大整数,双精度算术不再精确。
答案 1 :(得分:3)
我写的是假设Javascript对所有数字使用双精度浮点表示。
某些数字在浮点格式中具有精确表示,特别是所有整数,例如|x| < 2^53
。某些数字尤其不是诸如0.1或0.2的分数,其在二进制表示中变为无限分数。
如果所有操作数和操作结果都具有精确表示,那么使用==
比较结果是安全的。
相关问题:
What number in binary can only be represented as an approximation?
答案 2 :(得分:2)
具有可表示范围的整数可由机器完全表示,浮点数不是(嗯,大多数)。
如果通过“基本整数数学”你理解“特征”,那么是的,你可以假设正确实现算术是一个特征。
答案 3 :(得分:2)
原因是,您可以完全以二进制格式(0001,0010,0011,...)表示每个整数(1,2,3,...)
这就是整数总是正确的原因,因为0011 - 0001总是为0010。 浮点数的问题在于,点之后的部分无法精确地转换为二进制数。
答案 4 :(得分:1)
您说“工作”的所有情况都是您给出的数字可以用浮点格式表示完全的情况。您会发现添加0.25和0.5以及0.125也可以正常工作,因为它们也可以用二进制浮点数精确表示。
它只是不能达到0.1的值,你会得到看似不准确的结果。
答案 5 :(得分:1)
整数是准确的,因为不精确的结果主要来自我们写小数部分的方式,其次是因为许多有理数在任何给定的基数中都没有非重复的表示。
有关完整说明,请参阅:https://stackoverflow.com/a/9650037/140740。
答案 6 :(得分:0)
只有在向非常大的整数添加足够小的整数时,该方法才有效 - 即使在这种情况下,您也不能以“浮点”格式表示两个整数。
答案 7 :(得分:-1)
无法表示所有浮点数。这是由于编码方式。维基页面比我更好地解释了它:http://en.wikipedia.org/wiki/IEEE_754-1985。 因此,当您尝试比较浮点数时,应使用delta:
myFloat - expectedFloat < delta
您可以使用最小的可表示浮点数作为delta。