Perl does not distinguish between integer and floating-point numbers when doing arithmetic. Machine Arithmetic where the operands and the result are all integral is accurate as long as all values can be properly represented by the platform. Unfortunately, floating-point arithmetic is inherently imprecise, and can trip programmers who are not aware of its usage.

Noncompliant Code Example

This noncompliant code example appears to print ten very large numbers, and on 64-bit machines, it indeed does so.

However, when run on a 32-bit machine, the loop will never terminate. This is because the numbers, while integral, are too large to be represented internally as integers, so they are represented as 32-bit floating-point numbers. Even with 24-bit mantissas, the numbers are too large for an increment of 1 to be noticed. Consequently, the program forever prints out the number 1e+16.

my $x = 10000000000000000;  # 1e+16
for (my $y = $x; $y <= $x + 5; $y += 1) {
  print "$y\n";
}

Compliant Solution

This compliant solution ensures that the loop counter computation involves numbers less than 248 (that is, 281,474,976,710,656).

my $x = 10000000000000000;  # 1e+16
for (my $y = 0; $y <= 5; $y += 1) {
  my $z = $x + $y;
  print "$z\n";
}

On a 32-bit machine, this program terminates normally after printing the following:

1e+16
1e+16
1e+16
1e+16
1e+16
1e+16

Compliant Solution

This compliant solution uses the Bignum module to ensure precise computation. The Bignum module is available in CPAN, but became part of Perl's standard library for version 5.8.

use bignum;
my $x = 10000000000000000;  # 1e+16
for (my $y = $x; $y <= $x + 5; $y += 1) {
  print "$y\n";
}

On a 32-bit machine, this program terminates normally after printing the following:

10000000000000000
10000000000000001
10000000000000002
10000000000000003
10000000000000004
10000000000000005

Risk Assessment

Failing to understand the limitations of floating-point numbers can result in unexpected computational results and exceptional conditions, possibly resulting in a violation of data integrity.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

INT01-PL

medium

probable

high

P4

L3

Bibliography

 


4 Comments

  1. Just a note about the second compliant solution:

    The Bignum has been added to Perl Standard Library in Perl 5.14 and on. Now it is a pragmatic module.

    Regards.

    1. Added a note to this info...thanks!

    2. Anonymous

      Actually bignum was added to core in 5.8.0 not 5.14.0

      use corelist next time to check for when a module was added to core.

       

      Unrelated:

      Why is bignum using a version specific search.cpan.org link and perlnumber using a metacpan link?

       

      perlnumber should probably be perldoc.perl.org link http://perldoc.perl.org/perlnumber.html

      (http://p3rl.org/perlnumber will redirect to the same place)

      bignum should be one of the following ( ordered from most preferred to least preferred. )

      I would also recommend against specifying a person as it only matters who was allowed to upload the module to PAUSE at the time it was uploaded.

      ( You could use p3rl.org links )

      1. Thanks for the versioning info and the links. I updated the rule with them.