Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using sprintf to round float numbers

Tags:

perl

I have the following perl code and want to round the last diget i used sprintf but i get some weird result when the last digest is 5 i expect the rounding to be up but the actual result is different below an example :

   my $x = sprintf("%.1f",4.35);    -> expected 4.4
    my $y=     sprintf("%.1f",4.36); -> expected 4.4
    my $z = sprintf("%.1f",4.32);  -> expected 4.3

      print $x,"\n"; -> actual result 4.3 -> expected 4.4
      print $y,"\n"; -> actual result 4.4 -> ok
      print $z,"\n"; -> actual result 4.3 ->ok

how can i change the above code /or if there are another option to get the expected results ?

like image 356
user3019319 Avatar asked Jul 31 '26 11:07

user3019319


2 Answers

4.35 would get rounded to 4.4, but you actually have something slightly less than 4.35.


35/100 is periodic in binary just like 1/3 is periodic in decimal.

$ perl -E'say sprintf "%.20g", 0.35'
0.34999999999999998

Of course, the same applies to 4 35/100.

$ perl -E'say sprintf "%.20g", 4.35'
4.3499999999999996

As such, 0.35 and 4.35 cannot be represented exactly using a floating point number.


The following solution relies on the fact that 0.5 isn't periodic in binary (0.5 = 1/2 = 2-1, a finite sum of powers of 2):

$ perl -E'
   say sprintf("%.0f", sprintf("%.15g", $_ * 10)) / 10
      for 4.35, 4.36, 4.32;
'
4.4
4.4
4.3
like image 117
ikegami Avatar answered Aug 02 '26 13:08

ikegami


% perl -E 'printf("%.1f\n", $_) for ( 4.35, 4.350000001 )'
4.3
4.4

4.35 is actually 4.34999999999999999

A kludge might be:

% perl -E 'printf("%.1f\n", $_ + 1e-15) for ( 4.35, 4.350000001 )'
4.4
4.4
like image 26
woolstar Avatar answered Aug 02 '26 13:08

woolstar