Ho bisogno di fare un po 'di aritmetica con grandi numeri esadecimali qui sotto, ma quando provo a fare output ricevo messaggi di errore di overflow "Numero esadecimale> 0xffffffff non-portatile", messaggi su non portatile o il valore esadecimale massimo a 32 bit FFFFFFFF.Come posso eseguire l'aritmetica esadecimale/decimale a 64 bit E produrre un numero intero in HEX come stringa in Perl?
Tutto ciò implica che la lingua standard e le routine di output soddisfano solo i valori a 32 bit. Ho bisogno di valori a 64 bit e ho fatto molte ricerche, ma non ho trovato nulla che BOTH abilita l'aritmetica E emette il grande numero in esadecimale.
my $result = 0x00000200A0000000 +
(($id & 0xFFFFF) * 2) + (($id/0x100000) * 0x40000000);
Così, per $ id con i seguenti valori dovrei ottenere $result
:
$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004
Come posso fare questo?
Ecco i miei risultati di ricerca inconcludenti, con ragioni:
How can I sum large hexadecimal values in Perl? Vague, risposta non definitivamente preciso e nessun esempio.
Integer overflow non conclusiva
Integer overflow non conclusiva
bigint nessuna info su assegnazione, l'aritmetica o uscita
bignum esempi non è vicino al mio problema.
How can I sprintf a big number in Perl? esempio dato non è abbastanza informazioni per me: non trattare con esadecimale assegnazione o l'aritmetica.
Re: secret code generator Alcuni esempi che utilizzano Fleximal, menziona to_str al valore della produzione di variabile, ma 1) non vedo come è stato assegnato alla variabile e 2) ottengo errore "Impossibile chiamare il metodo" to_str " senza un pacchetto o oggetto riferimento" quando eseguo il mio codice utilizzando esso.
String to Hex Esempio di utilizzo di Math :: BigInt che non funziona per me - ancora ottenere errore di overflow.
Is there a 64-bit hex()? Ci siamo quasi - ma non si occupa emettere il gran numero in esadecimale, essa parla solo di decimali.
CPAN Math:Fleximal fa l'aritmetica, ma non sembra essere qualsiasi mezzo effettivamente uscita il valore esadecimale ancora in
sprintf sembra non essere in grado di far fronte a numero maggiore di 32 bit, ottenere il messaggio FFFFFFFF saturo .
Edit: Aggiornamento - nuovo requisito e la soluzione fornita - non esitate a offrire commenti
Chas. La risposta di Owens è ancora accettata ed eccellente (la parte 2 funziona per me, non ho provato la versione 1 per il Perl più recente, sebbene inviterei altri a confermarlo).
Tuttavia, un altro requisito era quello di essere in grado di convertire indietro dal risultato all'id originale.
Quindi ho scritto il codice per fare questo, ecco la soluzione completa, incluso @Chas. soluzione Owens originale, seguita dalla realizzazione di questo nuovo requisito:
#!/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";
}
provare questo codice alla http://ideone.com/IMsp6.
output di 'perl -V: ivsize'? – ysth
Questo non è un messaggio di errore, è un avvertimento. In particolare, uno che il tuo codice potrebbe funzionare dove perl usa interi a 64 bit ma non dove usa interi a 32 bit. Se in effetti hai e avrai sempre interi a 64 bit, disabilitalo con 'no warnings" portable ";' – ysth
@ysth Questa è una pessima idea. Il codice non sarà più portatile allora. Disattivare gli avvisi disattivandoli è una cattiva pratica. Vedi la mia risposta per una soluzione migliore. –