Perl 转换为 int 错误但仅限于特定数字

发布于 2024-11-29 22:39:23 字数 332 浏览 1 评论 0原文

下面的 Perl 代码将浮点数转换为错误的整数

use strict;

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

其输出是:

29760722
00000000029760721

事实是,您可以将给定的数字更改为其他数字,并且它可以工作。

知道这里出了什么问题吗?还是 Perl 只是做错了?

感谢您的帮助!

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 simply do it wrong?

Thanks for your help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

虚拟世界 2024-12-06 22:39:23

这与常见问题解答相关(为什么我得到了很长的小数)。 $zahl 未正确舍入,它向下舍入到下一个较小的整数。

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.

凉薄对峙 2024-12-06 22:39:23

22/100 是二进制周期数,就像 1/3 是十进制周期数一样。将其精确地存储在浮点数中需要无限的存储空间。

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

intsprintf %d 截断小数,因此最终得到 29760721。printsprintf %f 四舍五入,这样你就可以获得想要的结果。

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

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
烟织青萝梦 2024-12-06 22:39:23

当您进行浮点乘以 100 时,结果将类似于 29760721.9999999963。然后,当您将 %d 转换为整数时,该值将被截断为 29760721

尝试 sprintf('%.10f', $zahl) 你应该能够看到这一点。

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.

飞烟轻若梦 2024-12-06 22:39:23

您必须非常小心浮点数并将它们视为定点。由于内置函数中可能发生各种转换,有时一个整数转换可能与另一个不完全相同。看来这种情况在 x.22 数字上发生过很多次:

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";

在我的系统上打印

n = 76269

需要仔细查看 Perl 源代码才能了解确切的转换差异在哪里。

我建议,如果您要使用定点数,请将它们全部转换为整数(使用通用转换函数,最好将源数字视为字符串),然后在 下使用它们使用integer; pragma 它将禁用浮点数。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文