سؤال

كيف يمكنني الجولة رقم عشري (النقطة العائمة) إلى أقرب عدد صحيح?

على سبيل المثال

1.2 = 1
1.7 = 2
هل كانت مفيدة؟

المحلول

والناتج من <لأ href = "http://perldoc.perl.org/perlfaq4.html#Does-Perl-have-a-round٪28)-function٪3f--What-about-ceil()- والطابق ()٪ 3F - أوقف وظائف٪ 3F "يختلط =" noreferrer "> perldoc -q round

<اقتباس فقرة> هل لدى بيرل وظيفة الجولة ()؟ ماذا عن سقف () والطابق ()؟ علم حساب المثلثات وظائف؟

تذكر أن int() مجرد باقتطاع نحو 0. التقريب لعدد معين من الأرقام، sprintf() أو <وأ href = "HTTP: / /perldoc.perl.org/functions/printf.html "يختلط =" noreferrer "> printf() عادة ما يكون أسهل طريق.

    printf("%.3f", 3.1415926535);       # prints 3.142

و POSIX وحدة (جزء من توزيع بيرل قياسي) الأدوات ceil()، floor()، وعدد من غيرها الرياضية والمثلثية المهام.

    use POSIX;
    $ceil   = ceil(3.5);                        # 4
    $floor  = floor(3.5);                       # 3

في 5،000-5،003 بيرلز، وقد تم حساب المثلثات في Math::Complex وحدة. مع 5.004، و Math::Trig وحدة (جزء من بيرل القياسية توزيع) تطبق الدوال المثلثية. داخليا كان يستخدم Math::Complex وحدة ويمكن لبعض وظائف خروج من محور الحقيقي في الطائرة المعقدة، على سبيل المثال جيب معكوس من 2.

يمكن التقريب في التطبيقات المالية لها آثار خطيرة، و يجب تحديد طريقة التقريب المستخدمة على وجه التحديد. في هذه الحالات، وربما يدفع لا يثقون أيهما التقريب نظام يجري التي تستخدمها بيرل، ولكن بدلا من ذلك تنفيذ وظيفة التقريب تحتاج نفسك.

لمعرفة السبب، لاحظ كيف عليك لا تزال لديها قضية في منتصف الطريق نقطة التناوب:

    for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i}

    0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7
    0.8 0.8 0.9 0.9 1.0 1.0

لا ألوم بيرل. انها هي نفسها كما في C. IEEE يقول ما علينا فعله هذه. أرقام بيرل التي هي الأعداد الصحيحة تحت 2**31 (على القيم المطلقة و32 بت آلات) يعمل الى حد كبير مثل الأعداد الصحيحة الرياضية. ليست مضمونة أرقام أخرى.

نصائح أخرى

بينما ليس على خلاف مع مجمع إجابات حول نصف الطريق علامات على أكثر شيوعا (وربما تافهة) الاستخدام:

my $rounded = int($float + 0.5);

التحديث

إذا كان من الممكن الخاصة بك $float أن تكون سلبية التالية الاختلاف سوف تنتج النتيجة الصحيحة:

my $rounded = int($float + $float/abs($float*2 || 1));

مع هذا الحساب -1.4 يتم تقريب إلى -1 ، -1.6 إلى -2 ، صفر لن تنفجر.

ويمكنك إما استخدام وحدة نمطية مثل الرياضيات :: جولة :

use Math::Round;
my $rounded = round( $float );

أو يمكنك أن تفعل ذلك بالطريقة الخام:

my $rounded = sprintf "%.0f", $float;

إذا قررت استخدام printf أو sprintf، لاحظ أنها تستخدم في نصف مستديرة لطريقة حتى .

foreach my $i ( 0.5, 1.5, 2.5, 3.5 ) {
    printf "$i -> %.0f\n", $i;
}
__END__
0.5 -> 0
1.5 -> 2
2.5 -> 2
3.5 -> 4

perldoc / perlfaq :

<اقتباس فقرة>   

وتذكر أن int() باقتطاع مجرد نحو 0. على التقريب ل   عدد معين من الأرقام، sprintf() أو printf() عادة ما يكون   أسهل طريق.

 printf("%.3f",3.1415926535);
 # prints 3.142
     

وحدة POSIX (جزء من توزيع بيرل قياسي)   تنفذ ceil()، floor()، وعدد من غيرها الرياضية   وظائف المثلثية.

use POSIX;
$ceil  = ceil(3.5); # 4
$floor = floor(3.5); # 3
     

في 5،000-5،003 بيرلز، وقد تم حساب المثلثات في وحدة Math::Complex.

     

ومع 5،004 وحدة Math::Trig (جزء من توزيع بيرل قياسي)> تنفذ الدوال المثلثية.

     

وداخليا يستخدم وحدة Math::Complex ويمكن لبعض وظائف كسر   الخروج من محور الحقيقي في الطائرة المعقدة، على سبيل المثال جيب معكوس من 2.

     

والتقريب في التطبيقات المالية يمكن أن يكون لها تداعيات خطيرة، والتقريب   يجب تحديد الطريقة المستخدمة على وجه التحديد. في هذه الحالات، وربما يدفع لا   يستخدم الثقة أيهما التقريب النظام بيرل، ولكن بدلا من ذلك تنفيذ   التقريب وظيفة تحتاج نفسك.

     

لمعرفة السبب، لاحظ كيف عليك لا تزال لديها قضية على التناوب في منتصف الطريق نقطة:

for ($i = 0; $i < 1.01; $i += 0.05)
{
   printf "%.1f ",$i
}

0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
     

لا ألوم بيرل. انها هي نفسها كما في C. IEEE يقول ما علينا فعله   هذه. أرقام بيرل التي هي الاعداد الصحيحه أقل من 2 ** 31 (على القيم المطلقة   و32 بت آلات) يعمل الى حد كبير مثل الأعداد الصحيحة الرياضية.   ليست مضمونة أرقام أخرى.

وأنت لا تحتاج إلى أي وحدة خارجية.

$x[0] = 1.2;
$x[1] = 1.7;

foreach (@x){
  print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
  print "\n";
}

وأنا قد تكون مفقودة وجهة نظرك، ولكن أعتقد أن هذا أنظف بكثير طريقة للقيام بنفس العمل.

وهذا ما يفعله هو السير من خلال كل رقم موجب في العنصر، طباعة العدد وصحيح مدورة في شكل ذكرتم. منها صحيح موجب مقربة رمز بسلسلة تستند فقط على الكسور العشرية. الباحث (_ $) أساسا <م> مستديرة أسفل عدد بذلك ($ <م> -int ($ )) يجسد العشرية. إذا العشرية هي (بالتعريف) أقل من 0.5 بدقة، ذهابا وأسفل الرقم. إن لم يكن، جولة المتابعة بإضافة 1.

وفيما يلي سوف أرقام الجولة الإيجابية أو السلبية لموقف عشري معينة:

sub round ()
{
    my ($x, $pow10) = @_;
    my $a = 10 ** $pow10;

    return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}

وفيما يلي عينة من خمس طرق مختلفة لsummate القيم. الأول هو طريقة ساذجة لأداء الجمع (وفشل). محاولات الثانية لاستخدام sprintf()، لكنه فشل أيضا. الاستخدامات الثالثة sprintf() بنجاح أثناء المباراة النهائية اثنين (4 و 5) استخدام floor($value + 0.5).

 use strict;
 use warnings;
 use POSIX;

 my @values = (26.67,62.51,62.51,62.51,68.82,79.39,79.39);
 my $total1 = 0.00;
 my $total2 = 0;
 my $total3 = 0;
 my $total4 = 0.00;
 my $total5 = 0;
 my $value1;
 my $value2;
 my $value3;
 my $value4;
 my $value5;

 foreach $value1 (@values)
 {
      $value2 = $value1;
      $value3 = $value1;
      $value4 = $value1;
      $value5 = $value1;

      $total1 += $value1;

      $total2 += sprintf('%d', $value2 * 100);

      $value3 = sprintf('%1.2f', $value3);
      $value3 =~ s/\.//;
      $total3 += $value3;

      $total4 += $value4;

      $total5 += floor(($value5 * 100.0) + 0.5);
 }

 $total1 *= 100;
 $total4 = floor(($total4 * 100.0) + 0.5);

 print '$total1: '.sprintf('%011d', $total1)."\n";
 print '$total2: '.sprintf('%011d', $total2)."\n";
 print '$total3: '.sprintf('%011d', $total3)."\n";
 print '$total4: '.sprintf('%011d', $total4)."\n";
 print '$total5: '.sprintf('%011d', $total5)."\n";

 exit(0);

 #$total1: 00000044179
 #$total2: 00000044179
 #$total3: 00000044180
 #$total4: 00000044180
 #$total5: 00000044180

ملاحظة يمكن استبدال أن floor($value + 0.5) مع int($value + 0.5) لإزالة الاعتماد على POSIX.

والأرقام السالبة يمكن أن تضيف بعض المراوغات أن الناس بحاجة إلى أن تكون على علم.

ونهج أسلوب printf تعطينا الأرقام الصحيحة، ولكنها يمكن أن تؤدي في بعض العروض ونيف. لقد اكتشفنا أن هذه الطريقة (في رأيي، بغباء) يضع في علامة - ما إذا كان ينبغي أو لا ينبغي. على سبيل المثال، -0.01 مقربا إلى مكان عشري واحد بإرجاع -0.0، بدلا من مجرد 0. إذا كنت تنوي القيام به على نهج أسلوب printf، وكنت أعلم أنك لا نريد العشرية، واستخدام %d وليس %f (عندما تحتاج الكسور العشرية، انها عندما يحصل على عرض متزعزع).

وعلى الرغم من انها صحيحة وللرياضيات لا صفقة كبيرة، لعرض يبدو مجرد غريب يظهر شيء من هذا القبيل "-0.0".

لطريقة الباحث، يمكن أن الأرقام السالبة تغيير ما تريد نتيجة لذلك (وإن كان هناك بعض الحجج التي يمكن تقديمها أنها صحيحة).

ووint + 0.5 يسبب مشاكل حقيقية مع أرقام-سلبية، إلا إذا كنت تريد أن تعمل بهذه الطريقة، ولكن أتصور أن معظم الناس لا. -0.9 ربما ينبغي أن جولة إلى -1، وليس 0. إذا كنت تعرف أنك تريد السلبي لتكون سقف بدلا من الكلمة ثم يمكنك أن تفعل ذلك في بطانة واحدة، وإلا، قد ترغب في استخدام الأسلوب كثافة مع قاصر تعديل (من الواضح أن هذا يعمل فقط للحصول على الأعداد الصحيحة مرة أخرى:

my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;

وبلدي حل لsprintf

if ($value =~ m/\d\..*5$/){
    $format =~ /.*(\d)f$/;
    if (defined $1){
       my $coef = "0." . "0" x $1 . "05";    
            $value = $value + $coef;    
    }
}

$value = sprintf( "$format", $value );

إذا كنت تشعر بالقلق فقط مع الحصول على قيمة عددية من نقطة عائمة كامل عدد (أي 12٬347،9999 أو 54٬321،0001)، وهذا النهج (المقترضة وتعديلها من فوق) سوف تفعل خدعة:

my $rounded = floor($float + 0.1); 
cat table |
  perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";' 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top