64-bit integers changed to floating point using JSON::XS::encode_json in Perl 64-bit integers changed to floating point using JSON::XS::encode_json in Perl json json

64-bit integers changed to floating point using JSON::XS::encode_json in Perl


I can replicate the problem if the integer is used somewhere in a floating point context. It's sufficient to use the number in a floating point operation, e.g. adding another float to it. Here's a sample script:

use strict;use JSON::XS qw(encode_json);use Devel::Peek;{    my $x = { number => 4_999_999_999_999_999};    Dump $x->{number};    warn encode_json $x; # encodes number as integer}{    my $x = { number => 4_999_999_999_999_999};    my $y = $x->{number} + 0.1;    Dump $x->{number};    warn encode_json $x; # encodes number as float}

On my FreeBSD amd64 system I get

SV = IV(0x80180a458) at 0x80180a468  REFCNT = 1  FLAGS = (IOK,pIOK)  IV = 4999999999999999{"number":4999999999999999} at /tmp/json3.pl line 22.SV = PVNV(0x80184d930) at 0x801813408  REFCNT = 1  FLAGS = (IOK,NOK,pIOK,pNOK)  IV = 4999999999999999  NV = 5e+15  PV = 0{"number":5e+15} at /tmp/json3.pl line 29.

A workaround is to use something like $x->{number} += 0; before the encode_json call — this would remove the NV value (the floating point value), and JSON::XS would again see only a IV (integer value).


I can't replicate your problem.

use Config      qw( %Config );use Devel::Peek qw( Dump );use JSON::XS    qw( encode_json decode_json );print $Config{uvsize} * 8, "-bit ints\n";my $n = 393074769794314240;printf("%.20g\n", 0+$n);Dump($n);my $json = encode_json([$n]);print "$json\n";Dump(decode_json($json)->[0]);

Outputs:

64-bit ints393074769794314240SV = IV(0x4c8d90) at 0x4c8da0  REFCNT = 1  FLAGS = (PADMY,IOK,pIOK)  IV = 393074769794314240[393074769794314240]SV = IV(0x1dd130) at 0x1dd140  REFCNT = 1  FLAGS = (IOK,pIOK)  IV = 393074769794314240

Unless I use it as a floating point number, say by replacing

printf("%.20g\n", 0+$n);

with

printf("%.20g\n", $n);

Going forward:

  • It's unlikely to help, but you could try upgrading JSON::XS.
  • Provide a minimal, runnable demonstration of the problem.
  • Provide the output of perl -V:ivsize.