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

发布于 2024-09-26 04:56:26 字数 4026 浏览 1 评论 0原文

我需要对下面的大十六进制数进行一些算术运算,但是当我尝试输出时,我收到溢出错误消息“十六进制数 > 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

我该如何做到这一点?

这是我不确定的研究结果,以及原因:


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

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";
}

http://ideone.com/IMsp6< 尝试此代码/a>.

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:


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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

英雄似剑 2024-10-03 04:56:26
#!/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";
}
#!/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;
}

The bigint pragma replaces the hex 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:

#!/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";
}
夕色琉璃 2024-10-03 04:56:26

ysth 的评论是正确的。使用 Debian Stretch 中的 Perl 进行 64 位算术的简短示例,不使用 Math::BigInt 又名“使用 bigint”:

#!/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。

The comment by ysth is right. Short example of 64-bit arithmetics using Perl from Debian stretch without Math::BigInt aka "use bigint":

#!/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;

The script prints 0xffffffffffffffffffffffffffffffd0.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文