2009-11-24 3 views
2

Я повторяю набор 32-разрядных шестнадцатеричных строк («DEADBEEF», «12345678» и т. Д.), И я пытаюсь суммировать их вместе, чтобы сформировать 32-разрядную контрольную сумму. Предположим, что переменная $temp загружена шестнадцатеричной строкой в ​​примере ниже.Как я могу суммировать большие шестнадцатеричные значения в Perl?

my $temp; 
my $checksum; 

for (...) 
{ 
    #assume $temp is loaded with a new hex string here 
    my $tempNum = hex ($temp); 
    $checksum += $tempNum; 
    $checksum &= 0xFFFFFFFF; 
    print printf("checksum: %08X",$checksum); 
} 

Первые несколько значений "7800798C", "44444444" и "44444444". Выход:

Контрольная сумма: 7800798C
контрольная сумма: BC44BDD0
контрольная сумма: FFFFFFFF
Контрольная сумма: FFFFFFFF

и т.д ..

, как вы можете видеть, что первые два сложений являются правильно, а затем он кажется насыщенным. Я что-то пропустил в отношении ограничения размера переменных Perl?

EDIT: Это реальный выход из сценария (строка является шестнадцатеричной строкой, значение десятичного преобразования этой строки, и контрольная сумма в результате выходе):

 
string: 7800798C, value: 2013297036, checksum 7800798C 
string: 44444444, value: 1145324612, checksum BC44BDD0 
string: 44444444, value: 1145324612, checksum FFFFFFFF 
string: 44444444, value: 1145324612, checksum FFFFFFFF 
string: 78007980, value: 2013297024, checksum FFFFFFFF 
string: 44444444, value: 1145324612, checksum FFFFFFFF 
+0

Странно, можете ли вы также напечатать $ tempNum в этом printf? – catwalk

+2

Этот код не генерирует контрольную сумму. Даже в Perl. :) – bzlm

+0

@bzlm: Я знаю об этом :) Это всего лишь часть операции контрольной суммы, остальная часть этого не кажется неправильной, поэтому я ее не включил. – dls

ответ

6

Это вопрос к Perl Monks.

Ответ кажется «use integer».

См. Оригинальный ответ на Perl Monks и perldoc integer.

$ perl -we 'use integer; printf("%08X\n", 0xFFFF_FFFF + 0xFFFF_FFFF)' 
+0

@ Синан: Мне нужно отменить ваше редактирование: -M менее известен, чем «использовать», а ссылка на perldoc для integer трудно заметить - это похоже на подсветку синтаксиса. – Arkadiy

+5

-M останется менее известным, если вы будете скрывать его от людей. :) –

6

Если ваш perl скомпилировано с 32-битными целыми числами, целыми операциями, результатом которых являются числа, превышающие 0xffffffff, что вызовет проблемы. Например:

my $x = hex '0x1234567890'; 
my $y = hex '0x1234567890'; 

print $x + $y, "\n"; 

Вы получите:

 
Integer overflow in hexadecimal number at ... 
Hexadecimal number > 0xffffffff non-portable at ... 

Использование bignum добавить прозрачную поддержку для больших целых чисел:

#!/usr/bin/perl 

use strict; use warnings; 
use bignum qw/hex/; 

my $x = hex '0x7800798C'; 
my $chk; 

for (1 .. 10) { 
    $chk += $x; 
    $chk &= 0xFFFFFFFF; 
    printf("checksum: %08X\n", $chk); 
} 

Убедитесь, что выход соответствует Вам ожидания:

 
checksum: 7800798C 
checksum: F000F318 
checksum: 68016CA4 
checksum: E001E630 
checksum: 58025FBC 
checksum: D002D948 
checksum: 480352D4 
checksum: C003CC60 
checksum: 380445EC 
checksum: B004BF78 

Без bignum, я получаю:

 
checksum: 7800798C 
checksum: F000F318 
checksum: FFFFFFFF 
checksum: FFFFFFFF 
checksum: FFFFFFFF 
... 
+0

Ваш ответ кажется немного загадочным для меня. Если он будет продолжать добавлять числа, а не = =, он получит число с плавающей запятой. – 2009-11-24 14:29:39

+0

, если бы мне было задано целое число, в котором были установлены младшие 32 бита, а & = это с 0xFFFFFFFF, я обязательно вернул бы 0xFFFFFFFF, но только для этого добавления. Добавление любого другого числа в это суммирование приведет к уникальному значению. Другими словами, я никогда не получу бесконечно 0xFFFFFFFF в этом суммировании. – dls

+4

Но вы не получите целого числа. В 32-битной системе добавление приводит к поплавке (NV), а затем, когда вы пытаетесь бить и целое число, Perl не знает, что делать, и решает, что целочисленный результат будет 0xFFFFFFFF. Это не идеальный выбор, но это выбор. 'use integer' решает проблему, отрицая продвижение по плаванию, поэтому integer + integer дает целое число (при необходимости обертывание). – hobbs

3

Какой результат вы хотите? &= удалит любые биты числа, превышающего 0xffffffff. Постоянно добавляя числа вместе, вы получаете большее и большее число, а затем & ed с 0xffffffff. В какой-то момент я ожидаю, что вы получите что-то другое, кроме 0xffffffff, нет? Но он никогда не может быть больше!

Возможно, лучший способ сделать контрольную сумму будет xor ваши номера вместе.

my $temp; 
my $checksum; 

for (...) 
{ 
    #assume $temp is loaded with a new hex string here 
    my $tempNum = hex ($temp); 
    $checksum ^= $tempNum; 
    print printf("checksum: %08X",$checksum); 
} 

Это сделает что-то уникальное для этих чисел.

3

Чтобы развернуть на Sinan's answer, операторы &=, а также формат %X зависят от размера целых чисел, скомпилированных в Perl. В этом случае максимальный размер составляет либо 4294967295, либо 0xFFFFFFFF.

В то время как ваши переменные могут содержать значения, превышающие это, они будут усечены до этого максимума, если они пройдены через &= или sprintf("%X").

+0

ОК, это имеет смысл. Предположим, что я хочу выполнить все эти добавления, а затем распечатать 32 младших значащих бита в новую переменную - как я могу это достичь? Я понимаю, что я не могу использовать & = или sprintf, как я и предполагал. – dls

+0

ahh - Я вижу, что Синан обратился к этому с помощью bignum - я попробую это ... – dls

Смежные вопросы