Perl代码使用until循环迭代从0.1到0.9失败的原因是什么?

huangapple go评论82阅读模式
英文:

Why does my Perl code fail to iterate from 0.1 to 0.9 using until loop?

问题

为什么它不起作用?

  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings;
  4. my $float = 0.1;
  5. until ($float == 1) {
  6. print("$float\n");
  7. $float += 0.1;
  8. sleep 1;
  9. }

它会继续打印 1、1.1、1.2 等等,但如果我将条件改为 until ($float == 0.2),它会执行一次 0.1 的迭代然后退出循环。

我想要打印从 0.1 到 0.9。

英文:

Why it doesn't work?

  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings;
  4. my $float = 0.1;
  5. until ($float == 1) {
  6. print("$float\n");
  7. $float += 0.1;
  8. sleep 1;
  9. }

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 在十进制中一样,因此不能通过浮点数精确表示。

  1. $ perl -e 'printf "%.100g\n", 0.1'
  2. 0.1000000000000000055511151231257827021181583404541015625

通过重复将其加在一起,您永远不会得到精确的 1

  1. $ perl -e 'my $acc = 0; for ( 1 .. 11 ) { $acc += 0.1; printf "%.100g\n", $acc }'
  2. 0.1000000000000000055511151231257827021181583404541015625
  3. 0.200000000000000011102230246251565404236316680908203125
  4. 0.3000000000000000444089209850062616169452667236328125
  5. 0.40000000000000002220446049250313080847263336181640625
  6. 0.5
  7. 0.59999999999999997779553950749686919152736663818359375
  8. 0.6999999999999999555910790149937383830547332763671875
  9. 0.79999999999999993338661852249060757458209991455078125
  10. 0.899999999999999911182158029987476766109466552734375
  11. 0.99999999999999988897769753748434595763683319091796875
  12. 1.0999999999999998667732370449812151491641998291015625

一个解决方法是使用十分之一。

  1. my $tenths = 1;
  2. until ( $tenths == 10 ) {
  3. my $float = $tenths / 10;
  4. say $float;
  5. ++$tenths;
  6. sleep 1;
  7. }

简化版本:

  1. for my $tenths ( 1 .. 9 ) {
  2. my $float = $tenths / 10;
  3. say $float;
  4. sleep 1;
  5. }

进一步简化:

  1. for my $tenths ( 1 .. 9 ) {
  2. say "0.$tenths";
  3. sleep 1;
  4. }
英文:

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.

  1. $ perl -e'printf "%.100g\n", 0.1'
  2. 0.1000000000000000055511151231257827021181583404541015625

By repeatedly adding that to itself, you never get exactly 1.

  1. $ perl -e'my $acc = 0; for ( 1 .. 11 ) { $acc += 0.1; printf "%.100g\n", $acc }'
  2. 0.1000000000000000055511151231257827021181583404541015625
  3. 0.200000000000000011102230246251565404236316680908203125
  4. 0.3000000000000000444089209850062616169452667236328125
  5. 0.40000000000000002220446049250313080847263336181640625
  6. 0.5
  7. 0.59999999999999997779553950749686919152736663818359375
  8. 0.6999999999999999555910790149937383830547332763671875
  9. 0.79999999999999993338661852249060757458209991455078125
  10. 0.899999999999999911182158029987476766109466552734375
  11. 0.99999999999999988897769753748434595763683319091796875
  12. 1.0999999999999998667732370449812151491641998291015625

One solution is to work with tenths.

  1. my $tenths = 1;
  2. until ( $tenths == 10 ) {
  3. my $float = $tenths / 10;
  4. say $float;
  5. ++$tenths;
  6. sleep 1;
  7. }

Simplified:

  1. for my $tenths ( 1 .. 9 ) {
  2. my $float = $tenths / 10;
  3. say $float;
  4. sleep 1;
  5. }

Further simplified:

  1. for my $tenths ( 1 .. 9 ) {
  2. say "0.$tenths";
  3. sleep 1;
  4. }

huangapple
  • 本文由 发表于 2023年6月2日 10:09:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76386723.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定