Мне нужно выполнить некоторые арифметические действия с большими шестнадцатеричными числами ниже, но при попытке вывода я получаю сообщения об ошибках переполнения "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
Как я могу это сделать?
Вот мои неубедительные результаты исследования с указанием причин:
Как я могу просуммировать большие суммы шестнадцатеричные значения в Perl? Расплывчатый ответ, неточный ответ и нет примера.
Целочисленное переполнение не окончательно
Целочисленное переполнение неубедительный
bigint нет информации о назначении, арифметике или выводе
bignum примеры, не близкие к моей проблеме.
Как я могу спринт с большим числом на Perl? приведенного примера недостаточно информации для меня: не имеет дело с шестнадцатеричным присваивание или арифметика.
Re: генератор секретного кода В некоторых примерах, использующих Fleximal, to_str упоминается для вывода значения переменная, но 1) Я не понимаю, как переменная была назначена и 2) я получаю ошибка «Невозможно вызвать метод to_str» без пакета или предмета ссылка "когда я запускаю свой код, используя это.
Строка в шестнадцатеричный Пример использования Math :: BigInt, который у меня не работает - все равно получаю ошибка переполнения.
Есть ли 64-битное шестнадцатеричное ()? Почти там - но не занимается вывод большого числа в шестнадцатеричном формате, он говорит только о десятичном.
CPAN Math: Fleximal выполняет арифметические операции, но, похоже, на самом деле нет никаких средств вывести значение в шестнадцатеричном формате
sprintf Кажется, не может справиться с числа больше 32 бит, получите насыщенное сообщение FFFFFFFF.
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 .