كيف يمكنني تعطيل العلمي عند العمل مع أعداد كبيرة جدا في بيرل؟
-
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;
إذا كنت تريد فقط أن نفعل ذلك لبعض الأعداد الصحيحة، يمكنك إنشاء الرياضيات :: BIGINT و> التحف.
وهناك أيضا bignum و <لأ href = "HTTP: //search.cpan. غزاله / حي / الرياضيات BigNum "يختلط =" noreferrer "> الرياضيات :: 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
ومع الأرقام التي كبير قد يكون لديك أرقام أكثر من الدقة تستخدم لتخزين الأرقام. (رؤية مثال بسيط runnable قد حل هذه المسألة).
إذا كنت حقا بحاجة الى ان نرى جميع الأرقام 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
ومن الواضح أن ليس صحيحا، وليس تحقيق٪ د التحويل والتي تسبب المشكلة، حاولت حل ترفع علم هنا:
#!/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 'د' تحويل كان يسبب مشكلة. القراءة على الرياضيات :: BIGINT يبدو تشير إلى أن يتم تخزين هذه الأرقام كسلاسل الداخل، لذلك تغيير لتحويل الصورة، إصلاح المشكلة:
#!/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
ولكن في ما يخص الإجابة كاريل، الذي كان IMHO الصحيح تقريبا، وهذا يمكن أيضا أن يتم ذلك دون استخدام BIGINT (BIGINT، BigNum، ...) عن طريق استخدام 'و' تحويل ولكن مع الدقة لمجموعة '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 );
}
وهذا يعمل أيضا للسؤال OP و:
perl -e 'printf "%.0f\n", 3 ** 333'
760988023132059813486251563646478824265752535077884574263917414498578085812167738721447369281049109603746001743233145041176969930222526036520619613114171654144