可能重复:
Why can't decimal numbers be represented exactly in binary?
problem with floating values
$var1 = 1;
for ( $i=0; $i<30; $i++ ) {
$var1 += 0.1;
$var2 = floor($var1);
$var3 = $var1-$var2;
if ( $var3 == 0.5 ) {
$var1 = $var2+1;
}
}
这个循环的意图是计算1.0,1.1,1.2,1.3,1.4,然后跳到2.0,2.1,2.2等
我遇到的问题是if
语句永远不会成立。此外,每十分之一的计算都会解决一些疯狂的科学答案。
我该如何解决这个问题?请帮忙!
编辑:我写了一个令人沮丧的匆忙的问题,这不止一个,我现在看到了。
问题的第一部分真的是“我怎样才能通过这个浮动点查询来完成这项工作”和“为什么这个问题甚至会发生!”
感谢所有好的回复,我将答案正确,这很容易回答“如何使这项工作”的核心问题。
使用0.49而不是0.5和&gt;而不是==做到了。原油而不是世界上最好的代码,但确实解决了原始问题。感谢大家,我将阅读其他回复并跟进以改进我的编码。
再一次,非常感谢。
答案 0 :(得分:5)
计算机无法准确表示浮点数,因为它们存储在二进制文件(基数2)中。所有浮标都会有一点点调整+/-。
见这里:http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
答案 1 :(得分:5)
这个给出了预期的结果:
$var1 = 1;
for ( $i=0; $i<30; $i++ ) {
$var1 += 0.1;
$var2 = (int)($var1);
$var3 = $var1-$var2;
if ( $var3 >= 0.45 ) {
$var1 = $var2+1;
}
echo $var1.' '.$var2.' '.$var3.'<br/>';
}
答案 2 :(得分:3)
二进制浮点数将选择近似值来表示它不能代表的基数10浮点数。因此,将float与float进行比较是不准确的(因为您无法确定其行为)。
您需要创建自己的base-10浮点数。如果您知道自己想要哪种精确度,就不难发明。在您的情况下,您只需要一个精确的数字。我们的基数为10的整数的公式为:value / 10表示精确位数的幂,即1,因此您的公式为= value / 10 。
执行算术运算与执行常规算术一样简单。只需将正常表示(指计算机使用的表示)转换为我们发明的表示。在您的情况下,$var1 += 0.1
会转向$var1 += 1
。
输出就像将表示转换为正常表示一样简单。在您的情况下,echo $var1 . '<br>';
会转向echo $var1 / 10 . '<br>';
$var1 = 10;
for ( $i=0; $i<30; $i++ ) {
echo $var1 / 10 . '<br>';
$var1 += 1;
if ($var1 % 10 == 5) {
$var1 = $var1+5;
}
}
答案 3 :(得分:2)
关于为什么会发生这种情况以及许多解决方案的大量信息。 PHP的基本设计目标之一是它的松散类型设计和隐式转换。本着这种精神,我认为解决这个问题的最简单方法之一是使用字符串比较。在你的情况下,这是一个很好的解决方案:
<?php
$var1 = 1;
for ( $i=0; $i<30; $i++ ) {
$var1 += 0.1;
$var2 = floor($var1);
$var3 = $var1 - $var2;
echo "$var1 | $var2 | $var3 \n";
if (number_format($var3, 1) == '0.5') {
echo "It's true\n";
$var1 = $var2 + 1;
}
}
答案 4 :(得分:1)
正确的解决方案是使用bcmath包:
$var1 = '1.0'; bcscale(1);
for ( $i = 0; $i < 30; $i++) {
$var2 = $var1;
for( $j = 0; $j < 5; $j++) {
echo $var2 . "\n";
$var2 = bcadd( $var2, '0.1');
}
$var1 = bcadd( $var1, '1');
}
答案 5 :(得分:0)
if语句可能永远不会仅仅由于浮点运算而执行 - 测试与浮点值的严格相等总是会带来这种风险。为什么不更改条件以检查变量是否位于以0.5为中心的小间隔内,以确保您捕获它???
答案 6 :(得分:-1)
保持简单,愚蠢并使用整数运算。
例如,您从1.1
开始为什么不:
for ( $i=1; $i<4; $i++ ) {
for ( $j=0; $j<5; $j++ ) {
$v = $i + ($j/10);
# ...
}
}