我尝试创建单元测试用例来检查我的表值是正确还是错误.
这是我的代码
echo $a = 2/9;
echo "<br>".$b=0.22222222222222;
echo "<br>".gettype($a);
echo "<br>".gettype($b);
if($a==$b){
echo "<br>". "equal";
}else echo "<br>". "Not equal";
if((string)$a==(string)$b){
echo "<br>". "equal";
}else echo "<br>". "Not equal";
Run Code Online (Sandbox Code Playgroud)
为什么我的第一个条件不起作用?我找不到原因.请帮我.
Dig*_*oss 10
该测试违反了浮点编程的基本规则:从不进行相等比较.
存在许多问题,这些问题源于浮点分数具有大但有限数量的比特的事实.这些问题通常被称为"舍入错误",尽管在大多数情况下它们不是错误,而是格式限制.
例如,由于我们在编程时编写数字的方式...作为十进制字符串...如果它们具有小数部分,我们可以编写的大多数数字在浮点格式中没有相应的表示.分数部分在基数2中重复.
这很大程度上排除了精确地比较浮点数,除了具有讽刺意味的是,在积分值之间.您需要实现模糊比较,例如abs(a - b) < epsilon.
而实际上,你2/9是不具有有限表示作为中奖情况要么十进制字符串或二进制字符串!1
要2/9成功地与一个常量进行相等比较,对程序,解释器和库的完美程度要求可以依赖.
例如,您必须输入2比您需要的更多的s,并且解释器必须使用比格式更精确的知识来舍入常量的低位.在执行操作时,机器实际上有一些额外的知识,但是在转换常量时解释器可能不会.此外,运行时舍入受各种选项的限制,像PHP这样的语言甚至可能无法准确指定不可代表的常量如何从源代码舍入到内部形式.
实际上它比这更糟糕,因为十进制字符串中的单个0.2/10 n组件也没有精确的二进制等价物.因此,它很可能是一个非常完美的和忠实的转换0.22222222222222的确不是实际的实际上等于尽力而为表示2/9.您不能将有限十进制字符串表示为在任何特定(有限)位数中最接近表示2/9的确切基数2分数.
(我们必须有一个关于不与浮点数进行相等比较的标准答案.)
1.每个机器分数是x/2 n形式的有理数.现在,常量是十进制的,每个十进制常数是x /(2 n*5 m)形式的有理数.5 米的数字是奇数,因此其中任何一个都没有2 n因子.只有当m == 0时,才能在分数的二进制和十进制扩展中得到有限的表示.例如,1.25确切的是因为它是5 /(2 2*5 0)但0.1不是因为它是1 /(2 0*5 1).对于有理数2/9,没有2 n 或 5 m因子.
浮点数很棘手,你需要限制小数点数.
$a = 2/9;
$b=0.22222222222222;
$a = number_format($a, 9);
$b = number_format($b, 9);
echo "a = " . $a . " and b = " . $b;
echo "<br>".gettype($a);
echo "<br>".gettype($b);
if($a==$b){
echo "<br>". "equal";
}else echo "<br>". "Not equal";
if((string)$a==(string)$b){
echo "<br>". "equal";
}else echo "<br>". "Not equal";
Run Code Online (Sandbox Code Playgroud)