3

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

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

我怎样才能防止这种情况发生?

谢谢你。

4

2 回答 2

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

于 2013-10-23T19:16:43.543 回答
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
于 2013-10-23T19:05:52.150 回答