आप पर्ल में एक फ्लोटिंग पॉइंट नंबर कैसे गोल करेंगे?


174

मैं एक पूर्णांक (दशमलव बिंदु) को निकटतम पूर्णांक पर कैसे गोल कर सकता हूं?

जैसे

1.2 = 1
1.7 = 2

जवाबों:


196

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

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

याद रखें कि 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

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


17
^ थरमा, छत को क्यों निकाला जाएगा? जहां तक ​​मुझे पता है, यह पोसिक्स या पर्ल में अपग्रेड नहीं है। प्रशस्ति पत्र की जरूरत!
सैम वाटकिंस

3
@Beginners, printfअगर आप एक चर में परिणाम चाहते हैं, का उपयोग करने का उपयोग करने की कोशिश मत करो sprintf... आशा है कि यह आपको कुछ डिबगिंग-समय बचाता है :-P
बोरिस Däppen

क्या मैं int()पीडीएल पर उपयोग कर सकता हूं ?
CinCout

1
POSIX का उपयोग करें; <br/> $ x = ($ x - फर्श ($ x)> = .5)? छत ($ x): फर्श ($ x);
जोसेफ आर्गेनिओ

136

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

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

अपडेट करें

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

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

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


4
... लेकिन यह नकारात्मक संख्याओं पर विफल रहता है: अभी भी बेहतर स्प्रिंट
एलेसेंड्रो

2
आह नहीं, यह नहीं है। एक ऋणात्मक संख्या को गोल करना आपको शून्य के करीब ले जाता है, आगे दूर नहीं। वे इन दिनों स्कूलों में क्या पढ़ा रहे हैं?
RET

6
@RET हाँ, यह नकारात्मक संख्याओं के साथ विफल होता है। $ फ्लोट = -1.4 परिणाम इस विधि के साथ 0 में। यही नहीं वे मेरे स्कूल में पढ़ाते थे। याद रखें कि int () शून्य की ओर बढ़ता है।
मछली पालन

4
@fishinear आप सही हैं, और मैं विधिवत पीछा कर रहा हूं। लेकिन मैंने ial तुच्छ उपयोग-मामले के लिए ’कहा। मेरा उत्तर सही कर दिया गया है।
RET

1
ध्यान दें कि यह $ फ्लोट = 0 है, यह फेल हो जाएगा :-)
चटाई

74

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

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

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

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

46

यदि आप प्रिंटफ या स्प्रिंटफ का उपयोग करने का निर्णय लेते हैं, तो ध्यान दें कि वे राउंड हाफ का उपयोग विधि से भी करते हैं।

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

इस पर ध्यान दिलाने के लिए धन्यवाद। अधिक सटीक रूप से, विधि का नाम 'राउंड हाफ टू ईवन' है।
जीन विंसेंट

प्रिंटफ, या स्प्रिंटफ का उल्लेख करने वाले सभी उत्तरों को इसका उल्लेख करना चाहिए।
7

यह एक अत्यंत महत्वपूर्ण जानकारी है। मेरे पास सॉफ़्टवेयर में कई बार सर्वरल बग थे क्योंकि मुझे लगता था कि 5 को हमेशा गोल किया जाएगा। मैंने अंततः पाया, क्यों पर्ल ने कभी वह नहीं किया जो मैं चाहता था। इस पर ध्यान दिलाने के लिए धन्यवाद।
बोरिस डैपेन

वास्तव में, यह ओएस पर निर्भर है! : विंडोज में यह दौर आधा यूनिक्स की तरह भी करने के लिए इच्छा के दौर आधा शून्य से दूर और इच्छा exploringbinary.com/...
APOC

9

देखिए 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

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


3

आपको किसी बाहरी मॉड्यूल की आवश्यकता नहीं है।

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

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

मुझे आपकी बात याद आ रही होगी, लेकिन मैंने सोचा कि यह एक ही काम करने के लिए बहुत क्लीनर तरीका था।

यह क्या करता है तत्व में प्रत्येक सकारात्मक संख्या के माध्यम से चलना, आपके द्वारा उल्लेखित प्रारूप में संख्या और गोल पूर्णांक को प्रिंट करना। कोड संबंधित गोल सकारात्मक पूर्णांक को केवल दशमलव के आधार पर समेटता है। int ($ _) मूल रूप से संख्या को गोल-डाउन करता है इसलिए ($ -int ($ )) दशमलव को कैप्चर करता है। यदि दशमलव (परिभाषा के अनुसार) सख्ती से 0.5 से कम है, तो संख्या को गोल-डाउन करें। यदि नहीं, तो 1 जोड़कर राउंड-अप करें।


1
एक बार फिर, एक प्राचीन प्रश्न का एक जटिल उत्तर के साथ क्यों जवाब दें जब आरईटी का उत्तर समान रूप से अच्छी तरह से काम करता है।
जोएल बर्गर

1
यह वास्तव में बहुत जटिल नहीं है, और आरईटी के उत्तर में गणित का एक समूह शामिल है जो कि ए) सैद्धांतिक रूप से अतिप्रवाह जोखिम, बी) अधिक समय लेता है, और सी) अनावश्यक रूप से आपके अंतिम मूल्य के लिए और अधिक एफपी अभेद्यता का परिचय देता है। रुको, कौन सा फिर से जटिल है? ;)
cptstubing06

2

निम्नलिखित दी गई दशमलव स्थिति में धनात्मक या ऋणात्मक संख्याओं को पूर्ण करेगा:

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

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

1

मूल्यों को समेटने के लिए पाँच विभिन्न तरीकों का एक नमूना निम्नलिखित है। पहला योग करने के लिए एक भोली तरीका है (और विफल रहता है)। दूसरा उपयोग करने का प्रयास करता है sprintf(), लेकिन यह भी विफल हो जाता है। तीसरा sprintf()सफलतापूर्वक उपयोग करता है जबकि अंतिम दो (4th और 5th) का उपयोग करता है 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


1

नकारात्मक संख्याएं कुछ विचित्रताएं जोड़ सकती हैं जिनके बारे में लोगों को जागरूक होने की आवश्यकता है।

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

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

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

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

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

0

स्प्रिंट के लिए मेरा समाधान

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

0

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

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

0

राउंड नंबर्स को पढ़ने के डॉक्यूमेंटेशन का भार, कई विशेषज्ञ सुझाव देते हैं कि आप अपनी खुद की राउंडिंग रूटीन लिख सकते हैं, क्योंकि आपकी भाषा के साथ प्रदान किया गया 'कैन्ड' संस्करण पर्याप्त सटीक नहीं हो सकता है, या इसमें त्रुटियाँ हो सकती हैं। हालांकि, मैं कल्पना करता हूं कि वे केवल एक, दो या तीन नहीं कई दशमलव स्थानों पर बात कर रहे हैं। इस बात को ध्यान में रखते हुए, यहां मेरा समाधान है (हालांकि बिल्कुल नहीं जैसा कि मेरी जरूरतों के अनुसार डॉलर प्रदर्शित करना है - प्रक्रिया बहुत अलग नहीं है, हालांकि)।

sub asDollars($) {
  my ($cost) = @_;
  my $rv = 0;

  my $negative = 0;
  if ($cost =~ /^-/) {
    $negative = 1;
    $cost =~ s/^-//;
  }

  my @cost = split(/\./, $cost);

  # let's get the first 3 digits of $cost[1]
  my ($digit1, $digit2, $digit3) = split("", $cost[1]);
  # now, is $digit3 >= 5?
  # if yes, plus one to $digit2.
  # is $digit2 > 9 now?
  # if yes, $digit2 = 0, $digit1++
  # is $digit1 > 9 now??
  # if yes, $digit1 = 0, $cost[0]++
  if ($digit3 >= 5) {
    $digit3 = 0;
    $digit2++;
    if ($digit2 > 9) {
      $digit2 = 0;
      $digit1++;
      if ($digit1 > 9) {
        $digit1 = 0;
        $cost[0]++;
      }
    }
  }
  $cost[1] = $digit1 . $digit2;
  if ($digit1 ne "0" and $cost[1] < 10) { $cost[1] .= "0"; }

  # and pretty up the left of decimal
  if ($cost[0] > 999) { $cost[0] = commafied($cost[0]); }

  $rv = join(".", @cost);

  if ($negative) { $rv = "-" . $rv; }

  return $rv;
}

sub commafied($) {
  #*
  # to insert commas before every 3rd number (from the right)
  # positive or negative numbers
  #*
  my ($num) = @_; # the number to insert commas into!

  my $negative = 0;
  if ($num =~ /^-/) {
    $negative = 1;
    $num =~ s/^-//;
  }
  $num =~ s/^(0)*//; # strip LEADING zeros from given number!
  $num =~ s/0/-/g; # convert zeros to dashes because ... computers!

  if ($num) {
    my @digits = reverse split("", $num);
    $num = "";

    for (my $i = 0; $i < @digits; $i += 3) {
      $num .= $digits[$i];
      if ($digits[$i+1]) { $num .= $digits[$i+1]; }
      if ($digits[$i+2]) { $num .= $digits[$i+2]; }
      if ($i < (@digits - 3)) { $num .= ","; }
      if ($i >= @digits) { last; }
    }

    #$num =~ s/,$//;
    $num = join("", reverse split("", $num));
    $num =~ s/-/0/g;
  }

  if ($negative) { $num = "-" . $num; }

  return $num; # a number with commas added
  #usage: my $prettyNum = commafied(1234567890);
}

सबरूटीन को अपने विनिर्देशों के अनुरूप बनाने के लिए, बस निम्नलिखित को संशोधित करें: if ($digit3 >= 5) { $digit3 = 0; $digit2++; if ($digit2 > 9) { $digit2 = 0; $digit1++; if ($digit1 > 9) { $digit1 = 0; $cost[0]++; } } } तो यह है: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; } तब बसreturn commafied($cost[0]);
जेरेत लॉयड

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.