Search code examples
perlfloating-pointprintffixed-point

sprintf : fixed point, big numbers and precision loss


I need to read some numbers in a database and write them into a text file using Perl.

In the table where are the numbers, the data format is defined as numeric (25,5) (it reads 25 digits, including 5 decimals).

I format the numbers in my file with a sprintf "%.5f", $myvalue to force 5 decimals and I just noticed that for greats values, there is a precision loss for numbers with more than 17 digits :

db   = 123.12345
file = 123.12345 (OK)

db   = 12345678901234891.12345
file = 12345678901234892.00000 (seems to be rounded to upper integer)

db   = 12345678901234567890.12345
file = 12345678901234567000.00000 (truncation ?)

What is Perl's greatest precision for fixed decimal numbers?

I am aware of the concepts and limitations of floating point arithmetic in general, but I am not a Perl monk and I do not know the internals of Perl so I don't know if it is normal (or if it is related at all to floating point). I am not sure either if it is a internal limitation of Perl, or a problem related to the sprintf processing.

Is there a workaround or a dedicated module that could help with that problem?

Some notable points :

  • this is an additional feature of a system that already uses Perl, so using another tool is not an option
  • the data being crunched is financial so I need to keep every cent and I cannot cope with a +/- 10 000 units precision :^S

Solution

  • Once again, I am finding a solution right after asking SO. I am putting my solution here, to help a future visitor :

    replace

    $myout = sprintf "%.5f", $myvalue;
    

    by

    use Math::BigFloat;
    $myout = Math::BigFloat->new($myvalue)->ffround( -5 )->bstr;