Je dois faire un peu d'arithmétique avec de grands nombres hexadécimaux ci-dessous, mais quand j'essaye de produire je reçois des messages d'erreur de débordement "nombre hexadécimal> 0xffffffff non-portable", messages au sujet de non portable, FFFFFFFF.Comment est-ce que je peux faire l'arithmétique hexagonale/décimale de 64 bits ET produire un nombre entier dans HEX comme chaîne en Perl?
Tout cela implique que les routines de langage et de sortie standard ne traitent que des valeurs de 32 bits. J'ai besoin de valeurs de 64 bits et j'ai fait beaucoup de recherches, mais je n'ai rien trouvé qui permette à l'arithmétique ET produit le grand nombre en hexadécimal.
my $result = 0x00000200A0000000 +
(($id & 0xFFFFF) * 2) + (($id/0x100000) * 0x40000000);
Donc, pour $ id avec les valeurs suivantes je devrais $result
:
$id = 0, $result = 0x00000200A0000000
$id = 1, $result = 0x00000200A0000002
$id = 2, $result = 0x00000200A0000004
Comment puis-je faire cela?
Voici mes résultats de recherche non concluants, les raisons pour lesquelles:
How can I sum large hexadecimal values in Perl? Vague, répond pas définitivement précis et aucun exemple.
Integer overflow non concluante
Integer overflow non concluante
bigint pas d'info sur l'attribution, l'arithmétique ou la sortie
bignum exemples pas près de mon problème.
How can I sprintf a big number in Perl? exemple donné ne suffit pas d'informations pour moi: ne traite pas avec affectation hex ou arithmétique.
Re: secret code generator Quelques exemples en utilisant Fleximal, mentionne to_str à la variable valeur de sortie de mais 1) Je ne vois pas comment la variable a été affecté et 2) Je reçois erreur « Impossible d'appeler la méthode » to_str " sans un paquet ou un objet référence" lorsque je cours mon code en utilisant il.
String to Hex Exemple d'utilisation Math :: BigInt qui ne fonctionne pas pour moi - encore obtenir erreur de débordement.
Is there a 64-bit hex()? Près de là - mais ne traite pas de sortir le grand nombre en hexadécimal, il ne parle que de décimales.
CPAN Math:Fleximal l'arithmétique ne fait, mais il ne semble pas être un moyen pour réellement sortie la valeur encore en hex
sprintf ne semble pas être en mesure de faire face à plus grand nombre que 32 bits, obtenez le message FFFFFFFF saturé .
Edit: Mise à jour - nouvelle exigence et la solution fournie - s'il vous plaît ne hésitez pas à faire des commentaires
Chas. La réponse d'Owens est toujours acceptée et excellente (la partie 2 fonctionne pour moi, je n'ai pas essayé la version 1 de Perl, mais j'inviterais d'autres personnes à la confirmer).
Cependant, une autre exigence était de pouvoir convertir en retour du résultat à l'ID d'origine.
J'ai donc écrit le code pour faire ceci, voici la solution complète, y compris @Chas. Owens solution originale, suivie par la mise en œuvre de cette nouvelle exigence:
#!/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";
}
essayer ce code à http://ideone.com/IMsp6.
sortie de 'perl -V: ivsize'? – ysth
Ce n'est pas un message d'erreur, c'est un avertissement. Plus précisément, celui que votre code peut fonctionner où perl utilise des entiers 64 bits mais pas où il utilise des entiers 32 bits. Si en fait vous avez et aurez toujours des entiers de 64 bits, désactivez-le avec 'aucun avertissement" portable ";' – ysth
@ysth C'est une mauvaise idée. Le code ne sera plus portable alors. Faire taire les avertissements en les éteignant est une mauvaise pratique. Voir ma réponse pour une meilleure solution. –