我该如何做64位十六进制/十进制算术,并在Perl中输出十六进制的完整数字作为字符串?
我需要做一些低于大十六进制数的算术,但是当我尝试输出时,我得到溢出错误消息“十六进制数字> 0xffffffff不可移植”,有关不可移植的消息或最大32位十六进制值FFFFFFFF。我该如何做64位十六进制/十进制算术,并在Perl中输出十六进制的完整数字作为字符串?
所有这些都意味着标准语言和输出例程只能处理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 例子没有接近我的问题没有资料。
给出的例子是不够的信息对我来说:不处理十六进制 赋值或算术。
Re: secret code generator 使用Fleximal一些例子,提到了to_str到 可变输出值,但是1)我没有看到 变量是如何分配的,2)我得到 错误“无法调用” to_str“ 没有包或对象 参考”当我运行我的代码使用 它。
String to Hex 使用数学:: BigInt有的例子 不为我工作 - 仍然得到 溢出错误。
Is there a 64-bit hex()? 快到了 - 但不与 处理以十六进制输出大量, 只小数会谈。
CPAN Math:Fleximal 做算术,但似乎没有要任何方式实际上 输出十六进制仍值
sprintf 似乎并不能够应付 数字更大比32位,得到饱和的FFFFFFFF消息的 。
编辑:更新 - 新的要求和提供的解决方案 - 请随时提出意见
查斯。欧文斯的回答仍然被接受和优秀(第2部分为我工作,还没有尝试新的Perl的第1部分版本,但我会邀请其他人来确认它)。
但是,另一个要求是能够将返回从结果转换为原始ID。
所以我写了代码来做到这一点,下面是完整的解决方案,包括@Chas。欧文斯原来的解决方案,其次是实施这项新规定:
#!/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尝试这个代码。
#!/usr/bin/perl
use strict;
use warnings;
use bigint qw/hex/;
for my $id (0 ,1, 2) {
my $result = hex("0x00000200A0000000") +
(($id & 0xFFFFF) * 2) + (($id/0x100000) * 0x40000000);
printf "%d: %#016x\n", $id, $result;
}
的bigint
编译使用,可以处理的数字那么大的一个版本替换hex
功能。它也透明地让数学运算符处理大整数,而不是目标平台上的整数。
请注意,这只适用于Perl 5.10及更高版本。如果你运行的是早期版本的Perl 5,你可以试试这个:
#!/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) {
my $result = bighex("0x00000200A0000000");
$result += (($id & 0xFFFFF) * 2) + (($id/0x100000) * 0x40000000);
print "$id ", to_bighex($result), "\n";
}
'perl -V:ivsize'的输出? – ysth 2010-10-06 15:39:25
这不是一个错误消息,它是一个警告。具体来说,你的代码可能工作在perl使用64位整数但不使用32位整数的地方。如果实际上你有和将总是有64位整数,用'无警告'禁用它'';' – ysth 2010-10-06 15:42:48
@ysth这是一个坏主意。那么代码将不再是可移植的。通过关闭警告来消除警告是一种不好的做法。查看我的答案以获得更好的解决方案 – 2010-10-06 15:46:26