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
.