我的 Perl 版本支持 64 位。我从多个来源接收 JSON 数据,然后对其进行解码、处理,然后重新编码,以便将数据保存在 MySQL 队列中,以便由不同的服务器进一步处理。
所有数据都包括 64 位整数作为标识符。有时,在某些我不理解的情况下,64 位整数被JSON::XS::encode_json更改为浮点值。例如,393074769794314240
将更改为3.93074769794314e+17
.
我怎样才能防止这种情况发生?
谢谢你。
如果整数在浮点上下文中的某处使用,我可以复制该问题。在浮点运算中使用该数字就足够了,例如向其添加另一个浮点数。这是一个示例脚本:
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
}
在我的 FreeBSD amd64 系统上,我得到
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.
$x->{number} += 0;
一种解决方法是在调用之前使用类似的东西encode_json
——这将删除 NV 值(浮点值),而 JSON::XS 将再次只看到一个 IV(整数值)。
我无法复制你的问题。
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]);
输出:
64-bit ints
393074769794314240
SV = 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
除非我将它用作浮点数,否则通过替换
printf("%.20g\n", 0+$n);
和
printf("%.20g\n", $n);
往前走:
perl -V:ivsize
。