浮点数精度
这个问题在这里已经有了答案:
由于浮点运算!=实数运算。 对于一些花车a
和b
,由于不精确造成的差异的例子是(a+b)-b != a
。 这适用于使用浮动的任何语言。
由于浮点数是有限精度的二进制数,因此有一定数量的可表示数,这会导致精度问题和这样的意外。 这里有另一个有趣的阅读:每个计算机科学家应该知道什么是浮点运算。
回到你的问题,基本上没有办法准确地表示二进制的34.99或0.01(就像在十进制中,1/3 = 0.3333 ...),所以使用近似值代替。 为了解决这个问题,你可以:
对round($result, 2)
使用round($result, 2)
将其舍入到2个小数位。
使用整数。 如果这就是货币,比如说美元,那么存储35.00美元为3500和34.99美元为34.99美元,然后将结果除以100。
很遗憾PHP没有像其他语言那样的十进制数据类型。
像所有数字一样,浮点数字必须以0和1的字符串形式存储在内存中。 这一切都是计算机的一部分。 浮点与整数的不同之处在于我们如何解释0和1,当我们想看看它们时。
一位是“符号”(0 =正数,1 =负数),8位是指数(范围从-128到+127),23位是被称为“尾数”(分数)的数字。 所以(S1)(P8)(M23)的二进制表示具有值(-1 ^ S)M * 2 ^ P
“尾数”呈特殊形式。 在正常的科学记数法中,我们显示“一个地方”以及分数。 例如:
4.39×10 ^ 2 = 439
在二进制中,“一个地方”是一个单一的位。 由于我们忽略了所有最左侧的0(科学记数法)(我们忽略了任何微不足道的数字),所以第一位保证是1
1.101×2 ^ 3 = 1101 = 13
由于我们保证第一位将是1,所以在存储编号以节省空间时删除此位。 所以上面的数字存储为101(尾数)。 假设领先1
作为一个例子,我们来看看二进制字符串
00000010010110000000000000000000
打破它的组件:
Sign Power Mantissa
0 00000100 10110000000000000000000
+ +4 1.1011
+ +4 1 + .5 + .125 + .0625
+ +4 1.6875
应用我们简单的公式:
(-1^S)M*2^P
(-1^0)(1.6875)*2^(+4)
(1)(1.6875)*(16)
27
换句话说,00000010010110000000000000000000的浮点数是27(根据IEEE-754标准)。
但是,对于许多数字,没有确切的二进制表示。 很像1/3 = 0.333 ....重复一次,1/100是0.00000010100011110101110000 .....重复“10100011110101110000”。 但是,32位计算机无法将整个数字存储在浮点数中。 所以这是最好的猜测。
0.0000001010001111010111000010100011110101110000
Sign Power Mantissa
+ -7 1.01000111101011100001010
0 -00000111 01000111101011100001010
0 11111001 01000111101011100001010
01111100101000111101011100001010
(注意,使用2的补码产生负7)
应该立刻清楚01111100101000111101011100001010看起来不像0.01
但更重要的是,它包含一个重复小数的截断版本。 原始小数包含重复的“10100011110101110000”。 我们已将此简化为01000111101011100001010
通过我们的公式将这个浮点数转换回十进制数,我们得到0.0099999979(注意这是一个32位计算机,一个64位计算机会有更高的精度)
这里有很多关于为什么浮点数的工作方式的答案...
但几乎没有任何精确的说法(Pickle提到它)。 如果你想(或者需要)精确的精度,唯一的方法就是使用BC Math扩展(这实际上只是一个BigNum,任意精度实现......)。
要添加两个数字:
$number = '12345678901234.1234567890';
$number2 = '1';
echo bcadd($number, $number2);
将导致12345678901235.1234567890
...
这被称为任意精度数学。 基本上所有的数字都是为每个操作分析的字符串,并且操作是按照数字的方式进行的(考虑长分区,但是由库完成)。 所以这意味着它很慢(与常规的数学结构相比)。 但它非常强大。 你可以乘,加,减,除,寻找模和幂的任何数字,具有精确的字符串表示形式。
所以你不能以100%的精度做1/3
,因为它有一个重复的小数(因此是不合理的)。
但是,如果你想知道1500.0015
平方是多少:
使用32位浮点数(双精度)给出估计结果:
2250004.5000023
但是,bcmath给出了确切的答案:
2250004.50000225
这一切都取决于你需要的精度。
此外,在这里要注意的其他事项。 PHP只能表示32位或64位整数(取决于您的安装)。 所以如果一个整数超过本地int类型的大小(32位为21亿,9.2 x10 ^ 18或92亿十亿),PHP会将int转换为浮点数。 虽然这不是一个问题(因为所有小于系统浮点数的精度都可以直接表示为浮点数),但如果将两个数相乘,它将失去显着的精度。
例如,给定$n = '40000000002'
:
作为一个数字, $n
将是float(40000000002)
,这是正确的,因为它是完全表示的。 但是,如果我们将其平方,我们得到: float(1.60000000016E+21)
作为一个字符串(使用BC数学), $n
将完全是'40000000002'
。 如果我们平方,我们得到: string(22) "1600000000160000000004"
...
因此,如果您需要大数字的精度或有理数的小数点,您可能需要查看bcmath ...
链接地址: http://www.djcxy.com/p/27439.html