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

Мне нужно сделать некоторую арифметику с большими шестнадцатеричными числами ниже, но при попытке вывода я получаю сообщения об ошибках переполнения "Шестнадцатеричное число> 0xffffffff непереносимые", сообщения о непереносимых или максимальных 32-битных шестнадцатеричных числах.значение FFFFFFFF.

Все это подразумевает, что стандартный язык и выходные процедуры работают только с 32-битными значениями.Мне нужны 64-битные значения и я провел много исследований, но я ничего не нашел, чтобы ОБА включила арифметику и вывела большое число в шестнадцатеричном формате.

my $result = 0x00000200A0000000 +
             ( ( $id & 0xFFFFF ) * 2 ) + ( ( $id / 0x100000 ) * 0x40000000 );

Итак, для $ id со следующими значениями Iдолжен получить $result:

$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004

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

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

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

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

Однако, еще одно требование было уметьпреобразовать обратно из результата в исходный идентификатор.

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

1 Ответ

12 голосов
/ 06 октября 2010
#!/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";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...