Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Perl to split a float

Why did I lose precision using split? My goal is to get just the fractional part, all of it.

$a = 123456789.123456789;
@b = split(/\./, $a);
$baseDec = "." . $b[1];

Above gives $baseDec == .123457

But this gives the correct precision: Is it the right way to do it? CORRECTION: THIS GIVES THIS SAME BAD PRECISION! I did not properly test the code. Sorry!

$a = 123456789.123456789;
@b = split(/\./, $a);
$baseInt = $b[0];
$baseDec = $a - $baseInt;

Should I be using Math::BigFloat?

Edit: $a should be a string $a = "123456789.123456789"; and then the original code works. Until I figure out how to get my Perl to work with longdouble, I can't test the original question. The answer seems to be that I lost precision because $a is being stored in a double (52 bits ~ 15 decimal digits, as @Ben stated below). print $a gives 123456789.123457.

like image 565
dnvrdave Avatar asked Jan 08 '15 04:01

dnvrdave


3 Answers

You can use int:

 $a = 123456789.123456789;
 $baseDec = $a - int($a);
like image 148
René Nyffenegger Avatar answered Sep 30 '22 21:09

René Nyffenegger


You lost precision because 123456789.123456789 is a numeric literal which, by default, the Perl compiler stores in a double (52 bits, ~15 decimal digits) $a. Next, when @b = split(/\./, $a); runs, $a is implicitly coerced into a string before it can be split.

If your Perl were compiled to use longdoubles (See: perl -V:uselongdouble and perl -V:doublesize), the numeric literal would have been represented with 80 bits (~21 decimal digits) and string coercion.

like image 34
Ben Grimm Avatar answered Sep 30 '22 19:09

Ben Grimm


IF you're going to treat it as a string, do so all the way through. You wouldn't assign a string without quoting, right?

my $a = "123456789.123456789";
like image 37
GWP Avatar answered Sep 30 '22 19:09

GWP