英文:
Why does my Perl code fail to iterate from 0.1 to 0.9 using until loop?
问题
为什么它不起作用?
#!/usr/bin/env perl
use strict;
use warnings;
my $float = 0.1;
until ($float == 1) {
print("$float\n");
$float += 0.1;
sleep 1;
}
它会继续打印 1、1.1、1.2 等等,但如果我将条件改为 until ($float == 0.2)
,它会执行一次 0.1 的迭代然后退出循环。
我想要打印从 0.1 到 0.9。
英文:
Why it doesn't work?
#!/usr/bin/env perl
use strict;
use warnings;
my $float = 0.1;
until ($float == 1) {
print("$float\n");
$float += 0.1;
sleep 1;
}
It goes further 1, 1.1, 1.2 and so on, but if I give until ($float == 0.2) it makes one iteration 0.1 and quit from loop.
I'd like to print from 0.1 to 0.9
答案1
得分: 4
1/10 在二进制中是一个周期性数字,就像 1/3 在十进制中一样,因此不能通过浮点数精确表示。
$ perl -e 'printf "%.100g\n", 0.1'
0.1000000000000000055511151231257827021181583404541015625
通过重复将其加在一起,您永远不会得到精确的 1
。
$ perl -e 'my $acc = 0; for ( 1 .. 11 ) { $acc += 0.1; printf "%.100g\n", $acc }'
0.1000000000000000055511151231257827021181583404541015625
0.200000000000000011102230246251565404236316680908203125
0.3000000000000000444089209850062616169452667236328125
0.40000000000000002220446049250313080847263336181640625
0.5
0.59999999999999997779553950749686919152736663818359375
0.6999999999999999555910790149937383830547332763671875
0.79999999999999993338661852249060757458209991455078125
0.899999999999999911182158029987476766109466552734375
0.99999999999999988897769753748434595763683319091796875
1.0999999999999998667732370449812151491641998291015625
一个解决方法是使用十分之一。
my $tenths = 1;
until ( $tenths == 10 ) {
my $float = $tenths / 10;
say $float;
++$tenths;
sleep 1;
}
简化版本:
for my $tenths ( 1 .. 9 ) {
my $float = $tenths / 10;
say $float;
sleep 1;
}
进一步简化:
for my $tenths ( 1 .. 9 ) {
say "0.$tenths";
sleep 1;
}
英文:
1/10 is a periodic number in binary like 1/3 is in decimal, so it can't be represented exactly by a floating point number.
$ perl -e'printf "%.100g\n", 0.1'
0.1000000000000000055511151231257827021181583404541015625
By repeatedly adding that to itself, you never get exactly 1
.
$ perl -e'my $acc = 0; for ( 1 .. 11 ) { $acc += 0.1; printf "%.100g\n", $acc }'
0.1000000000000000055511151231257827021181583404541015625
0.200000000000000011102230246251565404236316680908203125
0.3000000000000000444089209850062616169452667236328125
0.40000000000000002220446049250313080847263336181640625
0.5
0.59999999999999997779553950749686919152736663818359375
0.6999999999999999555910790149937383830547332763671875
0.79999999999999993338661852249060757458209991455078125
0.899999999999999911182158029987476766109466552734375
0.99999999999999988897769753748434595763683319091796875
1.0999999999999998667732370449812151491641998291015625
One solution is to work with tenths.
my $tenths = 1;
until ( $tenths == 10 ) {
my $float = $tenths / 10;
say $float;
++$tenths;
sleep 1;
}
Simplified:
for my $tenths ( 1 .. 9 ) {
my $float = $tenths / 10;
say $float;
sleep 1;
}
Further simplified:
for my $tenths ( 1 .. 9 ) {
say "0.$tenths";
sleep 1;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论