我需要用下面的大十六进制数做一些算术,但是当我尝试输出时,我收到溢出错误消息“Hexadecimal number> 0xffffffff non-portable”,有关不可移植的消息,或最大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消息。
修改:更新 - 新要求和提供的解决方案 - 请随时提供评论
查斯。欧文斯的答案仍然被接受和优秀(第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处试用此代码。
答案 0 :(得分:12)
#!/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
pragma将hex
函数替换为可以处理大数字的版本。它还透明地使数学运算符处理大的int而不是目标平台上的int。
注意,这仅适用于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";
}
答案 1 :(得分:1)
ysth的评论是正确的。在不使用Math :: BigInt又名“ use bigint”的情况下使用Debian Stretch中的Perl进行64位算术的简短示例:
#!/usr/bin/perl -wwi
sub do_64bit_arith {
use integer;
my $x = ~2;
$x <<= 4;
printf "0x%08x%08x\n", $x>>32, $x;
}
do_64bit_arith();
exit 0;
该脚本将打印0xffffffffffffffffffffffffffffffd0。