开发者

Perl converts to int wrong but only with specific number

开发者 https://www.devze.com 2023-03-28 00:10 出处:网络
the following perl code converts a float number to the wrong integer number use strict; my $zahl =297607.22000;

the following perl code converts a float number to the wrong integer number

use strict;

my $zahl =297607.22000;
$zahl=$zahl * 100;
print "$zahl\n";
my $text=sprintf ("%017d",$zahl);
print $text;

The output of this is :

29760722
00000000029760721

The thing is, you can change the given number to other numbers and it works.

Any idea what is wrong here or does Perl sim开发者_C百科ply do it wrong?

Thanks for your help!


This is related to a FAQ (Why am I getting long decimals). $zahl is not rounded properly, it is rounded down to the next lower integer.


22/100 is a periodic number in binary just like 1/3 is a periodic number in decimal. It would take infinite storage to store it exactly in a floating point number.

$ perl -e'$_="297607.22000"; $_*=100; printf "%.20f\n", $_'
29760721.99999999627470970154

int and sprintf %d truncate decimals, so you end up with 29760721. print and sprintf %f round, so you can get the desired result.

$ perl -e'$_="297607.22000"; $_*=100; printf "%017.0f\n", $_'
00000000029760722


When you are doing your floating point multiplication by 100 the result will be something like 29760721.9999999963. Then when you do the %d conversion to an integer this is truncated to 29760721.

Try sprintf('%.10f', $zahl) and you should be able to see this.


You have to be really careful with floating point numbers and treating them as fixed point. Due to various conversions that may take place in the builtins, there may be times where one integer conversion is not exactly the same as another. It appears that this happens many times with x.22 numbers:

use strict;

my $n = 0;
for (0 .. 10_000_000) {
    my $float = 100 * "$_.22";

    my $str = "$float";
    my $int = int $float;

    if ($str ne $int) {
        $n++;
        #say "$float, $str, $int";
    }
}

say "n = $n";

which prints

n = 76269

on my system.

A careful look at the Perl source would be required to see where the exact conversion difference is.

I would recommend that if you are going to be working with fixed point numbers, to convert them all to integers (using a common conversion function, preferably looking at the source numbers as strings), and then work with them all under the use integer; pragma which will disable floating point numbers.

0

精彩评论

暂无评论...
验证码 换一张
取 消