printf/sprintf的Perl舍入错误

printf/sprintf的Perl舍入错误,perl,printf,rounding-error,Perl,Printf,Rounding Error,有谁能解释一下: #!/usr/bin/perl -w my $amount = 74.32 * 100.00; printf "Unformatted Amount:${amount}:\n"; printf " Formatted Amount:%.11d:\n", $amount; 输出如下: $ ./test.pl Unformatted Amount:7432: Formatted Amount:00000007431: 目前我已经停止使用printf和sprintf,因为我

有谁能解释一下:

#!/usr/bin/perl -w
my $amount = 74.32 * 100.00;

printf "Unformatted Amount:${amount}:\n";
printf " Formatted Amount:%.11d:\n", $amount;
输出如下:

$ ./test.pl
Unformatted Amount:7432:
  Formatted Amount:00000007431:
目前我已经停止使用printf和sprintf,因为我不信任它们。所以我改为这样做:

#!/usr/bin/perl -w
my $amount = 74.32 * 100.00;

$formatted_amount = "00000000000" . $amount;
$formatted_amount = substr($formated_amount,length($formatted_amount)-11,11);

printf "Unformatted Amount:${amount}:\n";
printf "  Formatted Amount:${formatted_amount}:\n";
这是可行的,但奇怪的是我为什么要这么做

我理解二进制数如何不能准确地表示所有以10为基数的数字,并且已经阅读了这个堆栈溢出条目:,但是我真的没有想到在这样一个看似简单的示例中会出现问题

另外,$amount的值是正确的。只是printf打印不正确

有什么想法吗?

我想printf应该放弃你

您希望%.11d的说明符做什么

小数点后的值是一个精度,表示

对于整数转换,指定精度意味着 数字本身的输出应该是零填充到零 此宽度,其中忽略0标志

如果您希望最小宽度为11个字符,而不仅仅是省略小数点-%11d将为您提供所需的宽度

Perl通过截断浮点数将其转换为整数,由于74.32*100.0略小于7432,因此int74.32*100.0为7431。如果要将浮点值四舍五入为最接近的整数,请使用精度为零的f格式说明符,如%11.0f

要将字段归零,请查看上述文档的标志部分。标志字符出现在宽度说明符之前:0使用零而不是空格右对齐

检查此程序

use strict;
use warnings;

my $amount = 74.32 * 100.00;

printf "Unformatted Amount:    ${amount}\n";
printf "Truncated Amount:      %d\n", $amount;
printf "High-precision Amount: %20.16f\n", $amount;
printf "Rounded Amount:        %.0f\n", $amount;
printf "Padded Amount:         %011.0f\n", $amount;
输出

我认为printf应该放弃你

您希望%.11d的说明符做什么

小数点后的值是一个精度,表示

对于整数转换,指定精度意味着 数字本身的输出应该是零填充到零 此宽度,其中忽略0标志

如果您希望最小宽度为11个字符,而不仅仅是省略小数点-%11d将为您提供所需的宽度

Perl通过截断浮点数将其转换为整数,由于74.32*100.0略小于7432,因此int74.32*100.0为7431。如果要将浮点值四舍五入为最接近的整数,请使用精度为零的f格式说明符,如%11.0f

要将字段归零,请查看上述文档的标志部分。标志字符出现在宽度说明符之前:0使用零而不是空格右对齐

检查此程序

use strict;
use warnings;

my $amount = 74.32 * 100.00;

printf "Unformatted Amount:    ${amount}\n";
printf "Truncated Amount:      %d\n", $amount;
printf "High-precision Amount: %20.16f\n", $amount;
printf "Rounded Amount:        %.0f\n", $amount;
printf "Padded Amount:         %011.0f\n", $amount;
输出


我很确定他的问题不是零,而是printf给他的是7431而不是7432。是否有小数点。@DeVadder:是的,我刚刚解决了这个问题。是的,我想要0填充的小数点,我的问题是从7432更改为7431。我不能使用%11d或%11.0f,因为它没有零填充。有趣的是%011s确实有效,%011.0f也是。好的,开始了解更多,谢谢你提供的关于截断的信息。我想我不应该假设浮点数和十进制数是一样的。如果有人还有什么要补充的话,我会把这个打开一段时间,但这看起来像是我会接受的答案。@BazzaDP:正如DeVadder所说,我已经更新了我的答案以显示,%011.0f是将浮点和零填充四舍五入到11位的正确格式说明符。我很确定他的问题不是零,而是printf给他的是7431而不是7432。是否有小数点。@DeVadder:是的,我刚刚解决了这个问题。是的,我想要0填充的小数点,我的问题是从7432更改为7431。我不能使用%11d或%11.0f,因为它没有零填充。有趣的是%011s确实有效,%011.0f也是。好的,开始了解更多,谢谢你提供的关于截断的信息。我想我不应该假设浮点数和十进制数是一样的。如果有人有任何进一步的补充,我会将此选项保留一段时间,但这看起来是我会接受的答案。@BazzaDP:正如DeVadder所说,并且我已经更新了我的答案,以显示,%011.0f是将浮点和零填充舍入到11位的正确格式说明符。Wierd。尤其是%.11f给出了正确的答案。显然,整数的转换被破坏了。因此,作为整数的变通方法,%11.0f似乎是可行的。@DeVadder:正如我所说,Perl总是截断浮点数以将其转换为整数。他们必须选择一种方法,而截断是最快的。如果你还需要别的东西,你可以很容易地编写出来。@Borodin:是的,我知道了,谢谢。我本以为将浮点数转换为整数和任何精度都是一样的。要么两个都截断,要么两个都圆。基本上,我总是假设%d在默认情况下与%.0f相同。如果要进行截断,我会希望%.5f在默认情况下小数点后有9个。@DeVadder:我不清楚你告诉我什么
你的最后一句话引起了一场争论。只有从浮点到整数的转换才会截断。正如我所说,它比任何形式的舍入都快得多,这也是C语言和我所知道的所有其他语言所做的。%.5f格式说明符不进行转换,因为它需要浮点值。它将在小数点后第五位舍入该值,因此0.123456的格式为0.12346,0.654321的格式为0.65432。那有用吗?维德。尤其是%.11f给出了正确的答案。显然,整数的转换被破坏了。因此,作为整数的变通方法,%11.0f似乎是可行的。@DeVadder:正如我所说,Perl总是截断浮点数以将其转换为整数。他们必须选择一种方法,而截断是最快的。如果你还需要别的东西,你可以很容易地编写出来。@Borodin:是的,我知道了,谢谢。我本以为将浮点数转换为整数和任何精度都是一样的。要么两个都截断,要么两个都圆。基本上,我总是假设%d在默认情况下与%.0f相同。如果截短是正确的方法,我希望%.5f在默认情况下小数点后有9个。@DeVadder:我不清楚你最后一句话的意思。只有从浮点到整数的转换才会截断。正如我所说,它比任何形式的舍入都快得多,这也是C语言和我所知道的所有其他语言所做的。%.5f格式说明符不进行转换,因为它需要浮点值。它将在小数点后第五位舍入该值,因此0.123456的格式为0.12346,0.654321的格式为0.65432。这有用吗?