如何在PHP中两个相等的数字不相等

时间:2022-09-18 13:22:33

I have two numbers which are supposed to be equal to return a difference, I doesn't make sense...

我有两个数字应该等于返回差异,我没有意义......

The only way to be able to reproduce this problem here I had to base64_encode my arrays,

能够在这里重现这个问题的唯一方法我必须base64_encode我的数组,

here is the script:

这是脚本:

basically the script will fix numbers like "1 234,5" to "1234.5" and does calculations, but at the ends it returns

基本上脚本会将“1 234,5”之类的数字修改为“1234.5”并进行计算,但最终会返回

            First Number: 4784.47
            Second Number: 4784.47
            Difference: 9.0949470177293E-13

I just don't understand????????

我只是不明白????????


            $aa = 'YTo3OntpOjA7YToxMDp7czoxMToiRGVzY3JpcHRpb24iO3M6MTI6IkvDqWsgc3rDoW1vayI7czo2OiJQZXJpb2QiO3M6MTI6IjA4LjEwLTA4LjEwLiI7czo2OiJBbW91bnQiO3M6MToiMSI7czoxMjoiRHVyYXRpb25UaW1lIjtzOjc6IjA6MDQ6MDAiO3M6MTI6Ik5ldFVuaXRQcmljZSI7czo1OiIzNSwyMCI7czo5OiJOZXRBbW91bnQiO3M6NjoiMTQwLDgwIjtzOjEwOiJWQVRQZXJjZW50IjtzOjM6IjI1JSI7czozOiJWQVQiO3M6NToiMzUsMjAiO3M6MTE6Ikdyb3NzQW1vdW50IjtzOjY6IjE3NiwwMCI7czo4OiJJdGVtQ29kZSI7czo0OiJCTFVFIjt9aToxO2E6MTA6e3M6MTE6IkRlc2NyaXB0aW9uIjtzOjE3OiJCZWxmw7ZsZGkgaMOtdsOhcyI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjIyLTA4LjExLiI7czo2OiJBbW91bnQiO3M6MjoiMTIiO3M6MTI6IkR1cmF0aW9uVGltZSI7czo3OiIwOjIxOjQzIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6IjMzMCwxMCI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjU6IjgyLDUyIjtzOjExOiJHcm9zc0Ftb3VudCI7czo2OiI0MTIsNjIiO3M6ODoiSXRlbUNvZGUiO3M6ODoiRklYX0ZMQVQiO31pOjI7YToxMDp7czoxMToiRGVzY3JpcHRpb24iO3M6MjM6IkVnecOpYiBtb2JpbCBlZ3lzw6lnw6FyIjtzOjY6IlBlcmlvZCI7czoxMjoiMDcuMjEtMDguMTEuIjtzOjY6IkFtb3VudCI7czoyOiI1MCI7czoxMjoiRHVyYXRpb25UaW1lIjtzOjc6IjE6MDE6MzgiO3M6MTI6Ik5ldFVuaXRQcmljZSI7czo1OiIxNSwyMCI7czo5OiJOZXRBbW91bnQiO3M6NjoiOTM2LDgzIjtzOjEwOiJWQVRQZXJjZW50IjtzOjM6IjI1JSI7czozOiJWQVQiO3M6NjoiMjM0LDIxIjtzOjExOiJHcm9zc0Ftb3VudCI7czo4OiIxIDE3MSwwNCI7czo4OiJJdGVtQ29kZSI7czo4OiJPRkZfRkxBVCI7fWk6MzthOjEwOntzOjExOiJEZXNjcmlwdGlvbiI7czoxOToiVm9kYWZvbmUgZWd5c8OpZ8OhciI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjE1LTA4LjEyLiI7czo2OiJBbW91bnQiO3M6MjoiMjAiO3M6MTI6IkR1cmF0aW9uVGltZSI7czo3OiIwOjU0OjM3IjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6Ijc2MywwNSI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjY6IjE5MCw3NiI7czoxMToiR3Jvc3NBbW91bnQiO3M6NjoiOTUzLDgxIjtzOjg6Ikl0ZW1Db2RlIjtzOjc6Ik9OX0ZMQVQiO31pOjQ7YToxMDp7czoxMToiRGVzY3JpcHRpb24iO3M6MTU6Ik5lbXpldGvDtnppIFNNUyI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjEzLTA4LjEzLiI7czo2OiJBbW91bnQiO3M6MjoiNDIiO3M6MTI6IkR1cmF0aW9uVGltZSI7czoxOiItIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMzAsNDAiO3M6OToiTmV0QW1vdW50IjtzOjg6IjEgMjc2LDgwIjtzOjEwOiJWQVRQZXJjZW50IjtzOjM6IjI1JSI7czozOiJWQVQiO3M6NjoiMzE5LDIwIjtzOjExOiJHcm9zc0Ftb3VudCI7czo4OiIxIDU5NiwwMCI7czo4OiJJdGVtQ29kZSI7czo3OiJTTVNfSU5UIjt9aTo1O2E6MTA6e3M6MTE6IkRlc2NyaXB0aW9uIjtzOjIzOiJTTVMgaMOhbMOzemF0b24ga8OtdsO8bCI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjI1LTA4LjExLiI7czo2OiJBbW91bnQiO3M6MjoiMTUiO3M6MTI6IkR1cmF0aW9uVGltZSI7czoxOiItIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6IjIyOCwwMCI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjU6IjU3LDAwIjtzOjExOiJHcm9zc0Ftb3VudCI7czo2OiIyODUsMDAiO3M6ODoiSXRlbUNvZGUiO3M6NzoiU01TX09GRiI7fWk6NjthOjEwOntzOjExOiJEZXNjcmlwdGlvbiI7czoyMjoiU01TIGjDoWzDs3phdG9uIGJlbMO8bCI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjE3LTA4LjEyLiI7czo2OiJBbW91bnQiO3M6MjoiMTUiO3M6MTI6IkR1cmF0aW9uVGltZSI7czoxOiItIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6IjE1MiwwMCI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjU6IjM4LDAwIjtzOjExOiJHcm9zc0Ftb3VudCI7czo2OiIxOTAsMDAiO3M6ODoiSXRlbUNvZGUiO3M6NjoiU01TX09OIjt9fQ==';

            $tt = 'YTozOntzOjE2OiJTdW1tYXJ5SXRlbU5ldHRvIjtzOjg6IjMgODI3LDU4IjtzOjE0OiJTdW1tYXJ5SXRlbVZBVCI7czo2OiI5NTYsODkiO3M6MTc6IlN1bW1hcnlJdGVtQnJ1dHRvIjtzOjg6IjQgNzg0LDQ3Ijt9';

            $a = unserialize(base64_decode($aa));
            $t = unserialize(base64_decode($tt));


            function calculate_call_fees($a,$t){

                $or_item = 0;

                foreach($a as $k => $r) {
                    $or_item += fix_num($r['GrossAmount']); 
                }        

                $br =  fix_num($t['SummaryItemBrutto']);   

                if($br>$or_item){
                    $diff = $br-$or_item;
                } else {
                    $diff = 0;
                }

                echo 'First Number: ' . $br.'<br/>';
                echo 'Second Number: ' . $or_item.'<br />';
                echo 'Difference: ' . $diff.'<br />';

                echo '<hr />';
                echo '<pre>';
                print_r($a);
                echo '</pre>';
                echo '<hr />';
                echo '<pre>';
                print_r($t);
                echo '</pre>';    

            }

            function fix_num($n){
                return floatval(str_replace(Array(" ",","),array("","."),$n));
            }

            calculate_call_fees($a,$t);

3 个解决方案

#1


2  

Using "equals" comparison with floating point numbers is dangerous because of floating point limited precision - you're liable to get small differences due to the rounding involved.

使用“等于”与浮点数的比较是危险的,因为浮点数限制精度 - 由于涉及舍入,您可能会得到小的差异。

Instead, if you want to see if two floating point numbers are "the same", just see if their difference is below a certain threshold:

相反,如果您想查看两个浮点数是否“相同”,只需查看它们的差异是否低于某个阈值:

if( abs($a - $b) < 0.00000001) {
    // a and b are "equal"
}

#2


1  

It is not just PHP. There is a general problem of representing fractional numbers in the computer. It's subject for various types of overflows, underflows, precision issues and so on. PHP's manual shed some light on the topic.

它不仅仅是PHP。在计算机中表示分数的一般问题。它受各种类型的溢出,下溢,精度问题等因素的影响。 PHP的手册阐述了这个主题。

The general rule - if you demand for two 'seem-equal' numbers to be guaranteed equal - don't use floating point data types (float, double), but fixed point (decimal, numeric)

一般规则 - 如果要求两个'似乎相等'的数字保证相等 - 不要使用浮点数据类型(浮点数,双精度数),而是使用浮点数(十进制数,数字数)

#3


1  

It appears as this is "Machine epsilon" issue: http://en.wikipedia.org/wiki/Machine_epsilon

它似乎是“机器epsilon”问题:http://en.wikipedia.org/wiki/Machine_epsilon

Try to compare the difference between them with 0.000001 instead of comparing them directly.

尝试用0.000001比较它们之间的差异,而不是直接比较它们。

#1


2  

Using "equals" comparison with floating point numbers is dangerous because of floating point limited precision - you're liable to get small differences due to the rounding involved.

使用“等于”与浮点数的比较是危险的,因为浮点数限制精度 - 由于涉及舍入,您可能会得到小的差异。

Instead, if you want to see if two floating point numbers are "the same", just see if their difference is below a certain threshold:

相反,如果您想查看两个浮点数是否“相同”,只需查看它们的差异是否低于某个阈值:

if( abs($a - $b) < 0.00000001) {
    // a and b are "equal"
}

#2


1  

It is not just PHP. There is a general problem of representing fractional numbers in the computer. It's subject for various types of overflows, underflows, precision issues and so on. PHP's manual shed some light on the topic.

它不仅仅是PHP。在计算机中表示分数的一般问题。它受各种类型的溢出,下溢,精度问题等因素的影响。 PHP的手册阐述了这个主题。

The general rule - if you demand for two 'seem-equal' numbers to be guaranteed equal - don't use floating point data types (float, double), but fixed point (decimal, numeric)

一般规则 - 如果要求两个'似乎相等'的数字保证相等 - 不要使用浮点数据类型(浮点数,双精度数),而是使用浮点数(十进制数,数字数)

#3


1  

It appears as this is "Machine epsilon" issue: http://en.wikipedia.org/wiki/Machine_epsilon

它似乎是“机器epsilon”问题:http://en.wikipedia.org/wiki/Machine_epsilon

Try to compare the difference between them with 0.000001 instead of comparing them directly.

尝试用0.000001比较它们之间的差异,而不是直接比较它们。