Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Perl inconsistent with sprintf rounding?

Here is a Perl script:

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my @numbers = qw(
    0.254
    0.255
    0.256
);

foreach my $number (@numbers) {
    my $rounded = sprintf '%.2f', $number;
    say "$number => $rounded";
}

foreach my $number (@numbers) {
    $number += 100;
    my $rounded = sprintf '%.2f', $number;
    say "$number => $rounded";
}

It outputs:

0.254 => 0.25
0.255 => 0.26
0.256 => 0.26
100.254 => 100.25
100.255 => 100.25
100.256 => 100.26

For me it is very strange that Perl is inconsistent with rounding. I expect that both number ending with .255 to be rounded as .26 It is true for 0.255, but it is false for the number 100.255.

Here is the quote from Perl Cookbook, http://docstore.mik.ua/orelly/perl/cookbook/ch02_04.htm,

sprintf . The f format lets you specify a particular number of decimal places to round its argument to. Perl looks at the following digit, rounds up if it is 5 or greater, and rounds down otherwise.

But I can't see any evidence that it is correct in http://perldoc.perl.org/functions/sprintf.html

Is it a bug in sprintf or Perl Cookbook is wrong? If it is desired behaviour, why does it work this way?

like image 858
bessarabov Avatar asked Dec 24 '16 11:12

bessarabov


People also ask

Does sprintf round?

Note that the value returned by sprintf is rounded, due to the specified print format.

How do you round to 2 decimal places in Perl?

Use the Perl function sprintf, or printf if you're just trying to produce output: # round off to two places $rounded = sprintf("%. 2f"", $unrounded);

What is Sprintf in Perl?

sprintf() function in Perl uses Format provided by the user to return the formatted string with the use of the values in the list. This function is identical to printf but it returns the formatted string instead of printing it.


1 Answers

If you add this line:

$number = sprintf '%.15f', $number;

before printing, you will have:

0.254000000000000 => 0.25
0.255000000000000 => 0.26
0.256000000000000 => 0.26
100.254000000000005 => 100.25
100.254999999999995 => 100.25
100.256000000000000 => 100.26

as you can see, 100.255 is not exactly 100.255 this is due to representation of float numbers.

like image 53
Toto Avatar answered Nov 16 '22 03:11

Toto