Comment désactiver la notation scientifique lorsque je travaille avec de très grands nombres en Perl?
-
07-07-2019 - |
Question
Considérez ce qui suit:
print 3 ** 333; #Yields 7.6098802313206e+158
Ma question est simple: comment désactiver la notation scientifique lorsque je travaille avec de très grands nombres? En gros, j'aimerais voir tous les chiffres transférés dans stdout
in extenso.
Est-ce possible?
La solution
Voir Math :: BigInt
use Math::BigInt;
$x = Math::BigInt->new("3");
print $x ** 333;
Sortie:
760988023132059809720425867265032780727896356372077865117010037035791631439306199613044145649378522557935351570949952010001833769302566531786879537190794573523
Autres conseils
Si vous voulez le faire pour tous les entiers de votre programme, vous pouvez simplement ajouter:
use bigint;
Si vous ne voulez le faire que pour certains entiers, vous pouvez créer Math :: BigInt objets.
Il existe également les bignum et Math :: BigNum si vous utilisez des flottants.
Pour les très petites valeurs, voir le code suivant:
my $value = 1e-07; # = 0.0000001
# NOPE
print $value; # prints 1e-07, $value is a number
print sprintf("%f", $value); # prints 0, $value is a number
print sprintf("%.10f", $value); # prints 0.0000001000, $value is a number
$value = sprintf("%.10f", $value);
print $value # prints 1e-07, $value is a number
# /NOPE
use bignum;
$value = ($value+0)->bstr();
print $value; # prints 0.0000001, $value is a string
no bignum;
print $value; # prints 0.0000001, $value is a string
# HOORAY
Avec des nombres aussi gros, vous pouvez avoir plus de chiffres que la précision utilisée pour stocker les nombres. (Voir un exemple simple pouvant être exécuté aurait résolu cette question.)
Si vous avez vraiment besoin de voir les 150 chiffres ou plus, utilisez les modules bigint (pour les entiers), bigrat (pour les nombres rationnels) et bignum (pour les nombres à virgule flottante).
Avait le même problème avec ce code:
#!/usr/bin/perl
use strict;
use warnings;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = 1; $x <= 64; $x++ ) {
my $y = (2 ** $x);
printf( "2 ^ %4d = %20d to %-20d or %20d\n",
$x, $y/-2, $y/2, $y );
}
Les deux dernières lignes où l’impression:
2 ^ 63 = -4611686018427387904 to 4611686018427387904 or -9223372036854775808
2 ^ 64 = -9223372036854775808 to -9223372036854775808 or -1
Évidemment pas correct, et ne réalisant pas que la conversion% d était la cause du problème, j'ai essayé la solution indiquée ici:
#!/usr/bin/perl
use strict;
use warnings;
use Math::BigInt;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = Math::BigInt->new('1'); $x <= 64; $x++ ) {
my $y = Math::BigInt->new(2 ** $x);
printf( "2 ^ %4d = %20d to %-20d or %20d\n",
$x, $y/-2, $y/2, $y );
}
C'est à ce moment-là que j'ai réalisé que la conversion printf 'd' était à l'origine d'un problème. En lisant Math :: BigInt, il semble suggérer que ces nombres sont stockés sous forme de chaînes à l'intérieur. Le passage à une conversion 's' a donc résolu le problème suivant:
#!/usr/bin/perl
use strict;
use warnings;
use Math::BigInt;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = Math::BigInt->new('1'); $x <= 64; $x++ ) {
my $y = Math::BigInt->new(2 ** $x);
printf( "2 ^ %4s = %20s to %-20s or %20s\n",
$x, $y/-2, $y/2, $y );
}
Maintenant, les deux dernières lignes imprimées correctement:
2 ^ 63 = -4611686018427387904 to 4611686018427387904 or 9223372036854775808
2 ^ 64 = -9223372036854775808 to 9223372036854775808 or 18446744073709551616
Mais en ce qui concerne la réponse de Karel, qui était à peu près correcte, à mon humble avis, cela pourrait également être fait sans utiliser BigInt (bigint, BigNum, ...) en utilisant la conversion 'f' mais avec la précision définie sur '0 'éliminer ces nombres décimaux:
#!/usr/bin/perl
use strict;
use warnings;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = 1; $x <= 64; $x++ ) {
my $y = (2 ** $x);
printf( "2 ^ %4d = %20.0f to %-20.0f or %20.0f\n",
$x, $y/-2, $y/2, $y );
}
Cela fonctionne également pour la question du PO:
perl -e 'printf "%.0f\n", 3 ** 333'
760988023132059813486251563646478824265752535077884574263917414498578085812167738721447369281049109603746001743233145041176969930222526036520619613114171654144