如何在 Perl 中进行 64 位十六进制/十进制算术并将十六进制完整数字输出为字符串?
我需要对下面的大十六进制数进行一些算术运算,但是当我尝试输出时,我收到溢出错误消息“十六进制数 > 0xffffffff 不可移植”、有关不可移植的消息或最大 32 位十六进制值 FFFFFFFF 。
所有这些都意味着标准语言和输出例程仅处理 32 位值。我需要 64 位值并做了很多研究,但我没有发现任何东西都可以启用算术并以十六进制输出大量数字。
my $result = 0x00000200A0000000 +
( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x40000000 );
因此,对于具有以下值的 $id,我应该得到 $result
:
$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004
我该如何做到这一点?
这是我不确定的研究结果,以及原因:
如何在 Perl 中对大的十六进制值求和? 模糊,答案不明确,没有示例。
整数溢出 非结论性
整数溢出 非结论性
bigint 没有有关赋值、算术或输出的信息
bignum 示例与我的问题不太接近。
回复:密码生成器 使用 Fleximal 的一些示例,提到 to_str 的输出值 变量,但1)我不明白如何 变量已分配,2)我得到 错误“无法调用方法“to_str” 没有包裹或物体 当我使用运行代码时参考”
字符串转十六进制 使用 Math::BigInt 的示例 不适合我 - 仍然得到 溢出错误。
有 64 位 hex() 吗? 几乎在那里 - 但没有处理 以十六进制输出大数, 它只讨论十进制。
CPAN 数学:Fleximal 进行算术运算,但似乎没有任何方法可以实际 输出仍为十六进制的值
sprintf 似乎无法应对 大于 32 位的数字,得到 饱和 FFFFFFFF 消息。
编辑:更新 - 新要求和提供的解决方案 - 请随时提供意见
Chas。 Owens 的回答仍然被接受并且非常出色(第 2 部分对我有用,还没有尝试过用于较新 Perl 的第 1 部分版本,尽管我会邀请其他人确认它)。
然而,另一个要求是能够将结果转换回到原始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";
}
I need to do some arithmetic with large hexadecimal numbers below, but when I try to output I'm getting overflow error messages "Hexadecimal number > 0xffffffff non-portable", messages about not portable, or the maximum 32-bit hex value FFFFFFFF.
All of which imply that the standard language and output routines only cope with 32 bit values. I need 64-bit values and have done a lot of research, but I found nothing that BOTH enables the arithmetic AND outputs the large number in hex.
my $result = 0x00000200A0000000 +
( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x40000000 );
So, for $id with the following values I should get $result
:
$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004
How can I do this?
Here is my inconclusive research results, with reasons why:
How can I sum large hexadecimal values in Perl? Vague, answer not definitively precise and no example.
Integer overflow
non conclusiveInteger overflow
non conclusivebigint
no info about assignment, arithmetic or outputbignum
examples not close to my problem.How can I sprintf a big number in Perl?
example given is not enough info for me: doesn't deal with hex
assignment or arithmetic.Re: secret code generator
Some examples using Fleximal, mentions to_str to output value of
variable but 1) I don't see how the
variable was assigned and 2) I get
error "Can't call method "to_str"
without a package or object
reference" when I run my code using
it.String to Hex
Example of using Math::BigInt which
doesn't work for me - still get
overflow error.Is there a 64-bit hex()?
Nearly there - but doesn't deal with
outputting the large number in hex,
it only talks of decimal.CPAN Math:Fleximal
does the arithmetic, but there doesn't seem to be any means to actually
output the value still in hexsprintf
Doesn't seem to be able to cope with
numbers greater than 32-bits, get the
saturated FFFFFFFF message.
Edit: Update - new requirement and supplied solution - please feel free to offer comments
Chas. Owens answer is still accepted and excellent (part 2 works for me, haven't tried the part 1 version for newer Perl, though I would invite others to confirm it).
However, another requirement was to be able to convert back from the result to the original id.
So I've written the code to do this, here's the full solution, including @Chas. Owens original solution, followed by the implementation for this new requirement:
#!/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";
}
Try out this code at http://ideone.com/IMsp6.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
bigint
编译指示替换了hex
函数,其版本可以处理如此大的数字。它还透明地使数学运算符处理大整数而不是目标平台上的整数。请注意,这仅适用于 Perl 5.10 及更高版本。如果您运行的是 Perl 5 的早期版本,您可以尝试以下操作:
The
bigint
pragma replaces thehex
function with a version that can handle numbers that large. It also transparently makes the mathematical operators deal with big ints instead of the ints on the target platform.Note, this only works in Perl 5.10 and later. If you are running an earlier version of Perl 5, you can try this:
ysth 的评论是正确的。使用 Debian Stretch 中的 Perl 进行 64 位算术的简短示例,不使用 Math::BigInt 又名“使用 bigint”:
脚本打印 0xffffffffffffffffffffffffffffffd0。
The comment by ysth is right. Short example of 64-bit arithmetics using Perl from Debian stretch without Math::BigInt aka "use bigint":
The script prints 0xffffffffffffffffffffffffffffffd0.