perl - आप पर्ल में एक फ़्लोटिंग पॉइंट नंबर कैसे घुमाते हैं?




floating-point rounding (8)

मैं दशमलव संख्या (फ़्लोटिंग पॉइंट) को निकटतम पूर्णांक में कैसे घुमा सकता हूं?

जैसे

1.2 = 1
1.7 = 2

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 );

आप या तो Math::Round जैसे मॉड्यूल का उपयोग कर सकते हैं:

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

या आप इसे कच्चे तरीके से कर सकते हैं:

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

जबकि अधिक सामान्य (और संभवतः मामूली) उपयोग-मामले के लिए, आधे रास्ते के निशान के बारे में जटिल उत्तरों से असहमत नहीं होने पर:

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

अद्यतन करें

यदि आपके $float नकारात्मक होने के लिए संभव है, तो निम्न भिन्नता सही परिणाम उत्पन्न करेगी:

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

इस गणना के साथ -1.4 को -1, और -1.6 से -2 तक गोल किया गया है, और शून्य विस्फोट नहीं होगा।


नकारात्मक संख्या कुछ quirks जोड़ सकते हैं कि लोगों को पता होना चाहिए।

printf -style दृष्टिकोण हमें सही संख्या देते हैं, लेकिन परिणामस्वरूप कुछ विषम प्रदर्शन हो सकते हैं। हमने पाया है कि यह विधि (मेरी राय में, बेवकूफ) एक संकेत में डालती है कि यह होना चाहिए या नहीं करना चाहिए या नहीं। उदाहरण के लिए, -0.01 एक दशमलव स्थान पर गोलाकार 0 0 की बजाय एक -0.0 देता है। यदि आप printf शैली दृष्टिकोण करने जा रहे हैं, और आप जानते हैं कि आप कोई दशमलव नहीं चाहते हैं, तो %d उपयोग करें और %f नहीं (जब आपको आवश्यकता हो decimals, यह तब होता है जब प्रदर्शन winky हो जाता है)।

हालांकि यह सही है और गणित के लिए कोई बड़ा सौदा नहीं है, प्रदर्शन के लिए यह अजीब दिखता है जैसे "-0.0"।

Int विधि के लिए, नकारात्मक संख्या परिणामस्वरूप आप जो चाहते हैं उसे बदल सकते हैं (हालांकि कुछ तर्क हैं जिन्हें वे सही कर सकते हैं)।

int + 0.5 वास्तविक समस्याओं के साथ वास्तविक समस्याओं का कारण बनता है, जब तक कि आप इसे इस तरह से काम नहीं करना चाहते हैं, लेकिन मुझे लगता है कि ज्यादातर लोग नहीं करते हैं। -0.9 शायद 1 तक नहीं होना चाहिए, 0 नहीं। यदि आप जानते हैं कि आप एक मंजिल के बजाय ऋणात्मक होना चाहते हैं तो आप इसे एक लाइनर में कर सकते हैं, अन्यथा, आप एक नाबालिग के साथ int विधि का उपयोग करना चाह सकते हैं संशोधन (यह स्पष्ट रूप से केवल पूरी संख्या वापस पाने के लिए काम करता है:

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

मानों को सारांशित करने के पांच अलग-अलग तरीकों का नमूना निम्नलिखित है। पहला सारांश (और विफल) करने के लिए एक बेवकूफ तरीका है। sprintf() का उपयोग करने के दूसरे प्रयास, लेकिन यह भी विफल रहता है। अंतिम दो (चौथा और 5 वां) उपयोग floor($value + 0.5) जबकि तीसरा sprintf() सफलतापूर्वक उपयोग करता है।

 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

ध्यान दें कि POSIX पर निर्भरता को हटाने के लिए floor($value + 0.5) int($value + 0.5) साथ प्रतिस्थापित किया जा सकता है।


यदि आप केवल पूरे फ्लोटिंग पॉइंट नंबर (यानी 12347.9 999 या 54321.0001) से पूर्णांक मान प्राप्त करने से चिंतित हैं, तो यह दृष्टिकोण (उधार और ऊपर से संशोधित) चाल करेगा:

my $rounded = floor($float + 0.1); 

perldoc -q round का आउटपुट

क्या पर्ल में एक गोल () फ़ंक्शन है? छत () और मंजिल () के बारे में क्या? ट्रिग फ़ंक्शन?

याद रखें कि int() केवल 0 की ओर छंटनी करता है। अंकों की एक निश्चित संख्या के लिए गोल करने के लिए, sprintf() या printf() आमतौर पर सबसे आसान मार्ग है।

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

POSIX मॉड्यूल (मानक पर्ल वितरण का हिस्सा ceil() floor() , 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

पर्ल दोष मत करो। यह सी के समान है। आईईईई का कहना है कि हमें यह करना है। पर्ल नंबर जिनकी पूर्ण मान 2**31 (32 बिट मशीनों पर) के तहत पूर्णांक हैं, वे गणितीय पूर्णांक की तरह काम करेंगे। अन्य संख्याओं की गारंटी नहीं है।


यदि आप 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




rounding