【发布时间】:2011-04-21 21:53:33
【问题描述】:
我需要在下面使用较大的十六进制数进行一些算术运算,但是当我尝试输出时,我收到溢出错误消息“十六进制数 > 0xffffffff 不可移植”、有关不可移植的消息或最大 32 位十六进制数值 FFFFFFFF。
所有这些都意味着标准语言和输出例程只能处理 32 位值。我需要 64 位值并进行了大量研究,但我没有发现 BOTH 启用算术并以十六进制输出大数字。
my $result = 0x00000200A0000000 +
( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x40000000 );
因此,对于具有以下值的 $id,我应该得到$result:
$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004
我该怎么做?
这是我不确定的研究结果,原因如下:
How can I sum large hexadecimal values in Perl? 含糊不清,回答不是很准确,也没有例子。
Integer overflow 无定论
Integer overflow 无定论
bigint 没有关于赋值、算术或输出的信息
bignum 与我的问题不相关的示例。
How can I sprintf a big number in Perl? 给出的示例对我来说信息不足:不处理十六进制 赋值或算术。
Re: secret code generator 一些使用 Fleximal 的例子,提到 to_str 到输出值 变量,但 1) 我不明白 变量被分配,2)我得到 错误“无法调用方法“to_str” 没有包裹或物品 参考”当我运行我的代码使用 它。
String to Hex 使用 Math::BigInt 的示例 对我不起作用 - 仍然得到 溢出错误。
Is there a 64-bit hex()? 几乎在那里 - 但不处理 以十六进制输出大数, 它只谈论小数。
CPAN Math:Fleximal 做算术,但实际上似乎没有任何方法 输出仍然是十六进制的值
sprintf 似乎无法应付 大于 32 位的数字,得到 饱和 FFFFFFFF 消息。
编辑:更新 - 新要求和提供的解决方案 - 请随时提供 cmets
查斯。 Owens 的回答仍然被接受并且非常出色(第 2 部分对我有用,还没有尝试过第 1 部分的新 Perl 版本,尽管我会邀请其他人确认)。
但是,另一个要求是能够将 back 从结果转换为原始 id。
所以我已经编写了代码来执行此操作,这是完整的解决方案,包括@Chas。 Owens 的原始解决方案,随后是针对此新要求的实施:
#!/usr/bin/perl
use strict;
use warnings;
use bigint;
use Carp;
sub bighex {
my $hex = shift;
my $part = qr/[0-9a-fA-F]{8}/;
croak "$hex is not a 64-bit hex number"
unless my ($high, $low) = $hex =~ /^0x($part)($part)$/;
return hex("0x$low") + (hex("0x$high") << 32);
}
sub to_bighex {
my $decimal = shift;
croak "$decimal is not an unsigned integer"
unless $decimal =~ /^[0-9]+$/;
my $high = $decimal >> 32;
my $low = $decimal & 0xFFFFFFFF;
return sprintf("%08x%08x", $high, $low);
}
for my $id (0 ,1, 2, 0xFFFFF, 0x100000, 0x100001, 0x1FFFFF, 0x200000, 0x7FDFFFFF ) {
my $result = bighex("0x00000200A0000000");
$result += ( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x40000000 );
my $clusterid = to_bighex($result);
# the convert back code here:
my $clusterid_asHex = bighex("0x".$clusterid);
my $offset = $clusterid_asHex - bighex("0x00000200A0000000");
my $index_small_units = ( $offset / 2 ) & 0xFFFFF;
my $index_0x100000_units = ( $offset / 0x40000000 ) * 0x100000;
my $index = $index_0x100000_units + $index_small_units;
print "\$id = ".to_bighex( $id ).
" clusterid = ".$clusterid.
" back to \$id = ".to_bighex( $index ).
" \n";
}
在http://ideone.com/IMsp6 试用此代码。
【问题讨论】:
-
这不是错误消息,而是警告。具体来说,您的代码可能在 perl 使用 64 位整数的情况下工作,但在使用 32 位整数的情况下不能工作。如果事实上您拥有并且将始终拥有 64 位整数,请使用
no warnings "portable";禁用它 -
@ysth 这是个坏主意。代码将不再是可移植的。通过关闭它们来消除警告是一种不好的做法。请参阅我的答案以获得更好的解决方案。
-
尽管接受了另一个答案,但我还是礼貌地回复您: 仅作记录:听取您关于没有警告“便携”的建议;但仍然收到错误消息:“./code.pl 第 9 行的十六进制数字中的整数溢出” - 使用的代码:#!/usr/bin/perl -w use strict;使用警告;没有警告“便携”;我的 $id = 1;我的 $result = 0x0000_0200_A000_0000 + ( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x4000_0000 );