如何进行64位十六进制/十进制算术并在HEX中输出一个完整的数字作为Perl中的字符串?

the*_*now 6 math perl 64-bit printf

我需要用下面的大十六进制数做一些算术,但是当我尝试输出时,我得到溢出错误消息"十六进制数> 0xffffffff非可移植",有关不可移植的消息,或最大32位十六进制值FFFFFFFF.

所有这些都意味着标准语言和输出例程只能处理32位值.我需要64位值,并做了很多研究,但我没有发现BOTH启用算术AND以十六进制输出大数字.

my $result = 0x00000200A0000000 +
             ( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x40000000 );
Run Code Online (Sandbox Code Playgroud)

因此,对于具有以下值的$ id,我应该得到$result:

$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

以下是我不确定的研究结果,原因如下:


编辑:更新 - 新要求和提供的解决方案 - 请随时提供评论

查斯.欧文斯的答案仍然被接受和优秀(第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";
}
Run Code Online (Sandbox Code Playgroud)

请在http://ideone.com/IMsp6上试用此代码.

Cha*_*ens 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;
}
Run Code Online (Sandbox Code Playgroud)

bigintpragma 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";
}
Run Code Online (Sandbox Code Playgroud)

  • 有时您不需要便携性。并且使用 bigint 锤子在 64 位支持 perl 上进行 64 位数学计算对我没有吸引力。您所做的 printf() 调用已经将可移植性排除在外。 (3认同)
  • @ysth 是的,我看到了并编写了第二个版本,该版本应该适用于所有 32 位机器。 (2认同)
  • 这意味着您使用的是 Perl 5.8.9 或更低版本。您将需要使用第二个版本。`hex` 替换仅适用于 Perl 5.10 或更高版本。 (2认同)