使用Perl中的JSON :: XS :: encode_json将64位整数更改为浮点数

时间:2013-10-23 18:19:19

标签: json perl integer 64-bit

我的Perl版本支持64位。我正在接收来自多个源的JSON数据,然后我正在解码它,处理它,然后我重新编码它以便将数据保存在MySQL队列中以供不同服务器进一步处理。

所有数据都包含64位整数作为标识符。有时,在某些我不理解的情况下,64位整数会被 JSON :: XS :: encode_json 更改为浮点值。例如,393074769794314240将更改为3.93074769794314e+17

如何防止这种情况发生?

谢谢。

2 个答案:

答案 0 :(得分:3)

如果在浮点上下文中的某处使用整数,我可以复制该问题。在浮点运算中使用该数字就足够了,例如添加另一个浮点数。这是一个示例脚本:

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(整数)值)。

答案 1 :(得分:2)

我无法复制你的问题。

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);

前进:

  • 它不太可能有所帮助,但您可以尝试升级JSON :: XS。
  • 提供最小的,可运行的问题演示。
  • 提供perl -V:ivsize
  • 的输出
相关问题