Zaid Zaid - 1 month ago 12
Perl Question

Is %s the only format that will allow printf to display big integers correctly?

I just spent an epoch figuring out that my big integer was fine and that

's
%d
/
%u
were not up to the task of displaying it:

use strict;
use warnings;
use bigint;
use List::Gen;

*factorial = do {use bigint; <[..*] 1, 1..>->code};

my $value = factorial(32);
printf "%d\n", $value; # -1
printf "%u\n", $value; # 18446744073709551615
printf "%s\n", $value; # 263130836933693530167218012160000000


I wouldn't be surprised if the answer is no, just wanted to confirm it.

Answer

This was surprisingly hard to track down. I didn't see anything obvious in the docs, so I went to the source. The printf function is implemented (at the bottom of a long call stack) by the C function Perl_sv_vcatpvfn_flags. It appears as if this function assumes the number will fit in an IV or a UV. They are defined by

typedef IVTYPE IV;
typedef UVTYPE UV;

Which is in turn defined by (at least on my Perl, I think this is configurable)

#define IVTYPE          long            /**/
#define UVTYPE          unsigned long           /**/

So, if your number won't fit in a long, then (%d) or in an unsigned long (%u), then a string (%s) is your only option. A bigger quesiton is why you are using printf in the first place. Are you formatting these numbers in some way other than printing them? If not, then print should just do the right thing.

Comments