Zaid
Zaid

Reputation: 37146

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 printf'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.

Upvotes: 3

Views: 1366

Answers (3)

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118148

Given that you have to use a specific library for the purpose of manipulating such numbers, there is no reason to expect that the builtin printf would handle them. Instead, you can use the library's conversion functions such as as_hex or bnstr. If you just want to print the number, use print "$value\n";.

Upvotes: 4

ikegami
ikegami

Reputation: 386331

Yes. %s is the only format for strings.


  • %%: Obviously no.
  • %c: Obviously no.
  • %s: Yes.
  • %d: Only if the number fits in a signed integer.
  • %u, %o, %x, %X, %b, %B: Only if the number fits in a unsigned integer.
  • %e, %E, %f, %g, %G, %a, %A: Only if the number fits in a floating point number.
  • %p: Obviously no.
  • %n: Obviously no.

Upvotes: 4

Chas. Owens
Chas. Owens

Reputation: 64919

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.

Upvotes: 11

Related Questions