Как мне выполнить 64-битную шестнадцатеричную / десятичную арифметику И вывести полное число в HEX в виде строки в Perl?

Мне нужно выполнить некоторые арифметические действия с большими шестнадцатеричными числами ниже, но при попытке вывода я получаю сообщения об ошибках переполнения "Hexadecimal число> 0xffffffff non-portable ", сообщения о непереносимости, или максимальное 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

Как я могу это сделать?

Вот мои неубедительные результаты исследования с указанием причин:


Edit: Update - новое требование и поставленное решение - пожалуйста, не стесняйтесь предлагать комментарии

Chas. Ответ Оуэнса по-прежнему принят и превосходен (часть 2 работает для меня, я не пробовал версию части 1 для более нового Perl, хотя я хотел бы предложить другим подтвердить это).

Однако другим требованием было иметь возможность конвертировать назад от результата к исходному идентификатору

Итак, я написал код для этого, вот полное решение, включая @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 .

6
задан Community 23 May 2017 в 12:08
поделиться