是否可以预测 Perl 的 decimal/float 数学何时会出错?

Is it possible to predict when Perl's decimal/float math will be wrong?

一方面,我理解 Perl 的浮点数是不精确的二进制表示,这导致 Perl 的数学有时是错误的。我不明白的是,为什么有时这些浮点数似乎给出了准确的答案,而其他时候却没有。 是否可以预测 Perl 的浮点数学何时会给出错误(即不准确的答案)?

例如,在下面的代码中,当减法是“16.12 - 15.13”时Perl的数学错误1次,当问题是“26.12 - 25.13”时错误2次,​​当问题是时错误20次“36.12 - 35.13”。此外,出于某种原因,在上述所有测试用例中,我们的减法问题(即 $subtraction_problem)的结果一开始是错误的,但随着我们加减的次数越多,结果就越正确从它(用$x)。这是没有意义的,为什么我们在算术题上加减越多,这个值就越有可能是正确的(即精确的)?

my $subtraction_problem = 16.12 - 15.13;
my $perl_math_failures = 0;
for (my $x = -25; $x< 25; $x++){
        my $result = $subtraction_problem +$x;
        print "$result\n";
        $perl_math_failures++ if length $result > 6;
}
print "There were $perl_math_failures perl math failures!\n";

None 这是 Perl 特有的。见 Goldberg:

Rounding Error

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation. The section Relative Error and Ulps describes how it is measured.

Since most floating-point calculations have rounding error anyway, does it matter if the basic arithmetic operations introduce a little bit more rounding error than necessary? That question is a main theme throughout this section. The section Guard Digits discusses guard digits, a means of reducing the error when subtracting two nearby numbers. Guard digits were considered sufficiently important by IBM that in 1968 it added a guard digit to the double precision format in the System/360 architecture (single precision already had a guard digit), and retrofitted all existing machines in the field. Two examples are given to illustrate the utility of guard digits.

The IEEE standard goes further than just requiring the use of a guard digit. It gives an algorithm for addition, subtraction, multiplication, division and square root, and requires that implementations produce the same result as that algorithm. Thus, when a program is moved from one machine to another, the results of the basic operations will be the same in every bit if both machines support the IEEE standard. This greatly simplifies the porting of programs. Other uses of this precise specification are given in Exactly Rounded Operations.