Как я могу отключить научную нотацию при работе с очень большими числами в Perl?
-
07-07-2019 - |
Вопрос
Рассмотрим следующее:
print 3 ** 333; #Yields 7.6098802313206e+158
Мой вопрос прост:Как я могу отключить научную нотацию при работе с очень большими числами?В принципе, я бы хотел, чтобы все цифры были сброшены в stdout
дословно.
Возможно ли это?
Решение
Видишь Math::BigInt
use Math::BigInt;
$x = Math::BigInt->new("3");
print $x ** 333;
Выходной сигнал:
760988023132059809720425867265032780727896356372077865117010037035791631439306199613044145649378522557935351570949952010001833769302566531786879537190794573523
Другие советы
Если вы хотите сделать это для всех целых чисел в вашей программе, вы можете просто добавить:
use bigint;
Если вы хотите сделать это только для нескольких целых чисел, вы можете создать Math :: BigInt объекты.
Существует также bignum и Math :: BigNum , если вы работаете с поплавками.
Для очень маленьких значений см. следующий код:
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
С большими числами вы можете иметь больше цифр, чем точность, используемая для хранения чисел. (Увидеть простой исполняемый пример решил бы этот вопрос).
Если вам действительно нужно увидеть все 150+ цифр, вы должны использовать модули bigint (для целых чисел), bigrat (для рациональных чисел) и bignum (для чисел с плавающей запятой).
У меня была та же проблема с этим кодом:
#!/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 );
}
Последние две строки, где печатается:
2 ^ 63 = -4611686018427387904 to 4611686018427387904 or -9223372036854775808
2 ^ 64 = -9223372036854775808 to -9223372036854775808 or -1
Очевидно, что это неправильно, и, не понимая, что преобразование% d стало причиной проблемы, я попробовал решение, помеченное здесь:
#!/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 );
}
Именно тогда я понял, что преобразование printf 'd' вызывает проблему. Читая Math :: BigInt, можно предположить, что эти числа хранятся в виде строк внутри, поэтому переход на преобразование 's' решает проблему:
#!/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 );
}
Теперь последние две строки напечатаны правильно:
2 ^ 63 = -4611686018427387904 to 4611686018427387904 or 9223372036854775808
2 ^ 64 = -9223372036854775808 to 9223372036854775808 or 18446744073709551616
Но в отношении ответа Карела, который был почти верным ИМХО, это также можно сделать без использования BigInt (bigint, BigNum, ...), используя преобразование 'f', но с точностью, установленной в '0 'чтобы удалить эти десятичные дроби:
#!/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 );
}
Это также работает для вопроса ОП:
perl -e 'printf "%.0f\n", 3 ** 333'
760988023132059813486251563646478824265752535077884574263917414498578085812167738721447369281049109603746001743233145041176969930222526036520619613114171654144