सीमा दो दशमलव बिंदुओं पर तैरती है


1690

मैं चाहता हूँ aकरने के लिए गोल होने के लिए 13.95

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

roundसमारोह तरह से मैं उम्मीद काम नहीं करता।



6
हम्म ... क्या आप मुद्रा का प्रतिनिधित्व करने की कोशिश कर रहे हैं? यदि हां, तो आपको डॉलर के लिए फ्लोट्स का उपयोग नहीं करना चाहिए। आप शायद पेनीज़ के लिए फ़्लोट्स का उपयोग कर सकते हैं, या जो भी मुद्रा की सबसे छोटी सामान्य इकाई आप मॉडल बनाने की कोशिश कर रहे हैं वह हो सकती है, लेकिन सबसे अच्छा अभ्यास एक दशमलव प्रतिनिधित्व का उपयोग करना है, जैसा कि HUAGHAGUAH ने अपने उत्तर में सुझाया था।
सिंगलनेशन इलीगेशन

63
फ्लोट में मुद्रा का प्रतिनिधित्व नहीं करना महत्वपूर्ण है। झंडे सटीक नहीं हैं। लेकिन पैसा या प्रतिशत राशि पूर्णांक हैं। इसलिए पूर्णांक मुद्रा का प्रतिनिधित्व करने का सही तरीका है।
दावउद तगावी-नजद

2
@ दावूदतगवी-नजद या उस बिंदु तक ... द डेसिमल टाइप
बेसिक

17
मैं शायद यहाँ बहुत देर से आ रहा हूँ, लेकिन मैं पूछना चाहता था, क्या पायथन के डेवलपर्स ने इस समस्या को हल किया है? क्योंकि जब मैं राउंड (13.949999999999999, 2) करता हूं, तो मुझे बस 13.95 मिलते हैं। मैंने इसे पायथन 2.7.6, साथ ही 3.4 में आज़माया है। यह काम करता हैं। यकीन नहीं होता है अगर 2009 में 2.7 भी था। शायद यह एक अजगर 2.5 बात है?
bad_keypoint 5

जवाबों:


1686

आप पुरानी समस्या में भाग रहे हैं फ़्लोटिंग पॉइंट नंबरों के साथ कि सभी नंबरों का प्रतिनिधित्व बिल्कुल नहीं किया जा सकता है। कमांड लाइन बस आपको मेमोरी से पूर्ण फ़्लोटिंग पॉइंट फॉर्म दिखा रही है।

फ्लोटिंग पॉइंट प्रतिनिधित्व के साथ, आपका गोल संस्करण समान संख्या है। चूंकि कंप्यूटर द्विआधारी हैं, वे एक पूर्णांक के रूप में फ्लोटिंग पॉइंट नंबर संग्रहीत करते हैं और फिर इसे दो की शक्ति से विभाजित करते हैं इसलिए 13.95 को 125650429603636838 / (2 ** 53) के समान फैशन में प्रतिनिधित्व किया जाएगा।

डबल सटीक संख्याओं में 53 बिट्स (16 अंक) सटीक और नियमित फ़्लोट्स में 24 बिट्स (8 अंक) सटीक होते हैं। अजगर में चल बिन्दु प्रकार पर दो परिशुद्धता का उपयोग करता है मान संग्रहीत करने के लिए।

उदाहरण के लिए,

>>> 125650429603636838/(2**53)
13.949999999999999

>>> 234042163/(2**24)
13.949999988079071

>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999

यदि आप केवल दो दशमलव स्थानों (उदाहरण के लिए एक मुद्रा मूल्य प्रदर्शित करने के लिए) के बाद हैं, तो आपके पास कुछ बेहतर विकल्प हैं:

  1. सेंटर्स में पूर्णांक और स्टोर वैल्यू का उपयोग करें, डॉलर में नहीं और फिर डॉलर में कनवर्ट करने के लिए 100 से विभाजित करें।
  2. या दशमलव की तरह एक निश्चित बिंदु संख्या का उपयोग करें ।

27
@ क्रिसियन संग्रहीत मूल्य के बीच एक मूलभूत अंतर है और आप उस मूल्य को कैसे प्रदर्शित करते हैं। आउटपुट को स्वरूपित करने से आपको आवश्यकतानुसार पैडिंग जोड़ने की अनुमति मिल सकती है, साथ ही कॉमा सेपरेटर इत्यादि भी जोड़ सकते हैं
बेसिक

22
ध्यान देने योग्य है कि "%.2f" % round(a,2)आप न केवल str()
प्रिंटफ

20
ऐसा क्यों है कि लोग हमेशा फ्लोटिंग-पॉइंट राउंडिंग पर मुद्रा ग्रहण करते हैं? कभी-कभी आप कम सटीकता के साथ काम करना चाहते हैं।
23

9
@ ब्रैडटेक: आपको यह समझने की आवश्यकता है कि द्विआधारी मूल्य (प्रकार का float) दशमलव संख्या का केवल निकटतम उपलब्ध सन्निकटन है (जो आप एक इंसान के रूप में परिचित हैं)। 0.245 के रूप में ऐसा (अंतिम रूप से प्रतिनिधित्व योग्य) द्विआधारी मूल्य नहीं है। यह बस अस्तित्व में नहीं है, और गणितीय रूप से मौजूद नहीं हो सकता है। बाइनरी मान जो 0.245 के सबसे करीब है, वह 0.245 से थोड़ा कम है , इसलिए स्वाभाविक रूप से यह गोल हो जाता है। इसी तरह, बाइनरी में 0.225 जैसी कोई चीज नहीं है, लेकिन बाइनरी वैल्यू जो 0.225 के सबसे करीब है, 0.225 से थोड़ा अधिक है , इसलिए स्वाभाविक रूप से यह गोल हो जाता है।
जॉन वाई

12
@ ब्रैडटेक: आपने शाब्दिक रूप से स्पष्टीकरण मांगा था। सबसे सीधा समाधान वास्तव में उपयोग करना है Decimal, और इस उत्तर में प्रस्तुत समाधानों में से एक था। दूसरा था अपनी मात्राओं को पूर्णांक में बदलना और पूर्णांक अंकगणित का उपयोग करना। ये दोनों दृष्टिकोण अन्य उत्तरों और टिप्पणियों में भी दिखाई दिए।
जॉन वाई

586

नए प्रारूप विनिर्देश हैं, स्ट्रिंग प्रारूप विशिष्टता मिनी-भाषा :

आप ऐसा कर सकते हैं:

"{:.2f}".format(13.949999999999999)

नोट 1: उपरोक्त रिटर्न एक स्ट्रिंग है। फ्लोट के रूप में प्राप्त करने के लिए, बस इसके साथ लपेटें float(...):

float("{:.2f}".format(13.949999999999999))

नोट 2: के साथ लपेटकर float()कुछ भी नहीं बदलता है:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True

17
अल्पविराम जोड़ने के लिए आप '{0:,.2f}'.format(1333.949999999)प्रिंट कर सकते हैं '1,333.95'
स्टीफन ब्लम

@ OnurYıldırım: हाँ, लेकिन आप इसे लपेट सकते हैं float(); float("{0:.2f}".format(13.9499999))
जोसेफ हारुश

5
@JossefHarush आप इसे फ्लोट () के साथ लपेट सकते हैं, लेकिन आपने कुछ भी प्राप्त नहीं किया है। अब आपके पास फिर से एक फ्लोट है, सभी समान खराबी के साथ। 13.9499999999999 और 13.95 समान फ्लोट हैं।
नेड बाथेल्ड

4
@NedBatchelder: मैं मानता हूं कि वे समान हैं, लेकिन यह फ्लोट को दो दशमलव बिंदुओं तक सीमित कर देता है :)
जोसेफ हारुश

8
वैसे, पायथन 3.6 के बाद से हम f- स्ट्रिंग्स का उपयोग कर सकते हैं:f"Result is {result:.2f}"
एंड्री सेमकिन

289

बिल्ट-इन round()काम करता है ठीक पायथन 2.7 या बाद में।

उदाहरण:

>>> round(14.22222223, 2)
14.22

की जाँच करें प्रलेखन


1
तो क्या मैं समझ सकता हूँ कि यह एक पायथन 2.7 असफल है? इस तरह के एक मूलभूत कार्य में v 2.7 से v 3 तक विभिन्न परिणाम क्यों होंगे?
माइक

लेकिन round(2.16, 1)देना 2.2क्यों अजगर सिर्फ एक की पेशकश truncateसमारोह
jiamo

उदाहरण के लिए, यदि आप मान को 2.675 से दो दशमलव स्थानों पर राउंड करने का प्रयास करते हैं, तो आपको यह >>> round(2.675, 2) 2.67 डॉक्सहोमथोन.org
tutorial

4
पायथन 3 प्रलेखन पृष्ठ से:Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
रिचर्ड डेली

ध्यान दें कि यदि आप किसी संख्या को प्रिंट करने के लिए इस पद्धति का उपयोग करने की कोशिश करते हैं जैसे कि 1.00000 तो यह केवल 1.0 प्रिंट आउट करेगी, चाहे कितने ही दशमलव बिंदु निर्दिष्ट हों।
जोश कोर्रेया

142

मुझे लगता है कि सबसे सरल दृष्टिकोण format()फ़ंक्शन का उपयोग करना है।

उदाहरण के लिए:

a = 13.949999999999999
format(a, '.2f')

13.95

यह दो दशमलव बिंदुओं पर गोल स्ट्रिंग के रूप में एक फ्लोट संख्या पैदा करता है।


97

उपयोग

print"{:.2f}".format(a)

के बजाय

print"{0:.2f}".format(a)

क्योंकि बाद में कई चर का उत्पादन करने की कोशिश करते समय आउटपुट त्रुटियां हो सकती हैं (टिप्पणियां देखें)।


2
यह बकवास है। दिए गए दो कथन Python 2.7 पर समान रूप से व्यवहार करते हैं, और केवल दूसरा कथन Python 2.6 पर मान्य है। (न तो बयान पायथन 3 या पायथन <2.6 में मान्य है।) पहले रूप में संक्षिप्तता के अलावा कोई फायदा नहीं है।
मार्क डिकिंसन

1
मेरा मतलब है, "{0: .2f} {0: .2f}" प्रिंट करें। प्रारूप (ए, बी) आउटपुट में गलती को जन्म देगा - यह दो बार 'मान' आउटपुट करेगा। जबकि "{:। 2f} {: .2f}" मुद्रित करें। प्रारूप (ए, बी) 'ए' और 'बी' मानों का उत्पादन करेगा।
एलेक्सी एंटोनेंको

2
पायथन 3 के लिए, आपको बस ब्रैकेट प्रिंट (...) जोड़ना होगा। और उनके भीतर मैंने जो लिखा है वह सही है।
एलेक्सी एंटोनेंको

"मेरा मतलब है," {0: .2f} {0: .2f} "प्रिंट करें। प्रारूप (ए, बी) आउटपुट में गलती की ओर ले जाएगा"। आह। खैर, यह एक अलग बयान है! शायद आपको अपना उत्तर संपादित करना चाहिए? (उदाहरण के लिए, वर्तमान उत्तर में "त्रुटि क्या बढ़ाता है", क्या आप एक ऐसे मामले का उदाहरण दे सकते हैं जहां दूसरा कथन एक अपवाद को उठाता है, लेकिन पहला नहीं?)
मार्क डिकिंसन

3
आप प्रिंट के बाद होंगे ("{0: .2f} {1: .2f}"। प्रारूप (ए, बी)) यदि आपके पास दो चर हैं
होवो

95

अधिकांश संख्याएँ फ़्लोट्स में बिलकुल नहीं दर्शाई जा सकतीं। यदि आप संख्या को गोल करना चाहते हैं, क्योंकि आपके गणितीय सूत्र या एल्गोरिथ्म की आवश्यकता है, तो आप गोल का उपयोग करना चाहते हैं। यदि आप केवल एक निश्चित परिशुद्धता के लिए प्रदर्शन को प्रतिबंधित करना चाहते हैं, तो गोल का भी उपयोग न करें और इसे केवल उस स्ट्रिंग के रूप में प्रारूपित करें। (यदि आप इसे कुछ वैकल्पिक गोलाई पद्धति के साथ प्रदर्शित करना चाहते हैं, और टन हैं, तो आपको दोनों दृष्टिकोणों को मिलाना होगा।)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

और अंत में, हालांकि शायद सबसे महत्वपूर्ण बात, अगर आप सटीक गणित चाहते हैं तो आप बिल्कुल भी तैरना नहीं चाहते हैं। सामान्य उदाहरण पैसे के साथ काम कर रहा है और 'सेंट' को पूर्णांक के रूप में संग्रहीत करना है।


68

नीचे दिए गए कोड को आज़माएं:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99

लेकिन सावधान रहना, एक के मूल्य अभी भी एक अस्थायी नाव है। यहां देखें - repl.it/LJs (राइट सेक्शन के ऊपर "रन सेशन" पर क्लिक करें)।
जीवनशैली

3
यदि आप इस दृष्टिकोण के साथ जाते हैं, तो आपको अधिक सटीक प्रतिनिधित्व के लिए 0.5 जोड़ना चाहिए। int (एक * 100 + 0.5) / 100.0; Math.ceil का उपयोग करना एक अन्य विकल्प है।
अरहुआको ar

3
@ शशांकसावंत: ठीक है, एक बात के लिए, प्रस्तुत उत्तर गोल नहीं है, यह छोटा है। अंत में आधा जोड़ने का सुझाव गोल होगा, लेकिन फिर roundपहले स्थान पर फ़ंक्शन का उपयोग करके ऐसा करने का कोई लाभ नहीं है। एक और बात के लिए, क्योंकि यह समाधान अभी भी फ्लोटिंग पॉइंट का उपयोग करता है, ओपी की मूल समस्या बनी हुई है, यहां तक ​​कि इस "समाधान" के "सही" संस्करण के लिए भी।
जॉन वाई

3
-1, यह roundफ़ंक्शन का एक अनावश्यक कार्यान्वयन है (जिसका उपयोग प्रश्न में किया गया था)।
अंतरजाल

4
@interjay जो round()ओपी के बताए अनुसार काम नहीं करता है।
पिथिकोस

57

TLDR;)

इनपुट / आउटपुट की राउंडिंग समस्या को निश्चित रूप से अजगर 2.7.0 और 3.1 द्वारा हल किया गया है

एक सही ढंग से गोल संख्या को पीछे और पीछे से परिवर्तित किया जा सकता है:
str -> float() -> repr() -> float() ...या Decimal -> float -> str -> Decimal
भंडारण के लिए एक दशमलव प्रकार अब आवश्यक नहीं है।


(स्वाभाविक रूप से, संचित अंतिम बिट त्रुटियों को समाप्त करने के लिए गोल संख्याओं के जोड़ या घटाव के परिणामस्वरूप गोल करना आवश्यक हो सकता है। एक स्पष्ट दशमलव अंकगणित अभी भी उपयोगी हो सकता है, लेकिन स्ट्रिंग द्वारा रूपांतरण str()(जो कि 12 मान्य अंकों के चक्कर के साथ है। ) पर्याप्त रूप से अच्छा है अगर कोई चरम सटीकता या क्रमिक अंकगणित संचालन की कोई चरम संख्या की आवश्यकता नहीं है।)

अनंत परीक्षण :

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

प्रलेखन

रिलीज़ नोट देखें पायथन 2.7 - अन्य भाषा चौथे पैराग्राफ को बदल देती है:

रूपांतरण फ्लोटिंग प्वाइंट नंबर और तार के बीच अब कर रहे हैं सही ढंग से गोल सबसे प्लेटफार्मों पर। ये रूपांतरण कई अलग-अलग जगहों पर होते हैं: फ़्लोट्स और जटिल संख्याओं पर str (); फ्लोट और जटिल निर्माणकर्ता; संख्यात्मक स्वरूपण; क्रमिक और डी-क्रमांकन तैरता है और जटिल संख्या का उपयोग करते हुए marshal, pickleऔर jsonमॉड्यूल; पायथन कोड में फ्लोट और काल्पनिक शाब्दिक का पार्सिंग; और दशमलव-से-फ्लोट रूपांतरण।

इस से संबंधित, फ़्लोटिंग-पॉइंट नंबर x का repr () अब सबसे छोटा दशमलव स्ट्रिंग के आधार पर एक परिणाम देता है जो सही राउंडिंग (राउंड-हाफ-टू-एंड-राउंडिंग मोड के साथ) के तहत वापस राउंड टू एक्स की गारंटी है । पहले इसने x को 17 दशमलव अंकों के चक्कर के आधार पर दिया था।

संबंधित मुद्दा


अधिक जानकारी:float पायथन 2.7 से पहले का प्रारूपण वर्तमान के समान था numpy.float64। दोनों प्रकार 52 बिट mantissa के साथ 64 बिट IEEE 754 डबल परिशुद्धता का उपयोग करते हैं । एक बड़ा अंतर यह है कि स्वरूपित किया गया है ताकि हर अंक महत्वपूर्ण हो; अनुक्रम अंतराल के बिना है और रूपांतरण प्रतिवर्ती है। बस: यदि आपके पास शायद एक numpy.float64 नंबर है, तो इसे मनुष्यों के लिए स्वरूपित करने के लिए सामान्य फ्लोट में रूपांतरित करें, संख्यात्मक प्रोसेसर के लिए नहीं, अन्यथा पायथन 2.7+ के साथ अधिक कुछ भी आवश्यक नहीं है।np.float64.__repr__ अक्सर एक अत्यधिक दशमलव संख्या के साथ स्वरूपित किया जाता है ताकि कोई भी बिट खो न जाए, लेकिन कोई भी वैध IEEE 754 नंबर 13.949999999999 और 13.950000000000001 के बीच मौजूद नहीं है। परिणाम अच्छा नहीं है और रूपांतरण repr(float(number_as_string))सुन्न के साथ प्रतिवर्ती नहीं है। दूसरी ओर:float.__repr__


क्यों उखाड़ा गया? सवाल पायथन float(डबल सटीक) और सामान्य के roundबारे में था, न कि numpy.double और स्ट्रिंग में इसके रूपांतरण के बारे में। प्लेन पायथन राउंडिंग वास्तव में पायथन 2.7 से बेहतर नहीं किया जा सकता है। अधिकांश उत्तर 2.7 से पहले लिखे गए हैं, लेकिन वे मोटे हैं, हालांकि वे मूल रूप से बहुत अच्छे थे। यह मेरे उत्तर का कारण है।
हाइनेकसर

53 बिट्स जब आप "छिपे हुए बिट" को शामिल करते हैं, जो 1कि "क्रमिक अंडरफ़्लो" के दौरान छोड़कर, निहित है ।
रिक जेम्स

यह राउंड की गलती नहीं है, यह डिस्प्ले फॉल्ट है।
रिक जेम्स

हाँ, यह अच्छी तरह से जाना जाता है। हालाँकि मुझे एक संदर्भ याद आता है यदि आप पायथन 2.7 रिलीज़ नोट्स या मेरे पाठ में किसी चीज़ पर आपत्ति करते हैं या कुछ भी नहीं करते हैं। यह इस प्रश्न के उद्देश्य से अधिक जटिल था। यह जोड़ा जाना चाहिए कि कुछ 32-बिट इंटेल चिप्स पर राउंड बग के कारण स्ट्रिंग से फ्लोट में रूपांतरण भी पायथन 2.7 में तय किया गया है और यह कि "राउंड () फ़ंक्शन भी अब सही ढंग से गोल है।" ( रिलीज नोट्स - 3.1 सुविधाओं को 2.7 के लिए वापस भेज दिया गया है )। क्या आप सहमत हो सकते हैं?
हाइनेसर

1
उफ़, वह a*bबनाम था b*a। लिंक के लिए धन्यवाद - नॉस्टेल्जिया।
रिक जेम्स

52

पायथन <3 (जैसे 2.6 या 2.7) के साथ, ऐसा करने के दो तरीके हैं।

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

लेकिन ध्यान दें कि पायथन संस्करणों के लिए 3 से ऊपर (उदाहरण 3.2 या 3.3), विकल्प दो को प्राथमिकता दी जाती है

विकल्प दो के बारे में अधिक जानकारी के लिए, मैं पायथन प्रलेखन से स्ट्रिंग प्रारूपण पर इस लिंक का सुझाव देता हूं ।

और विकल्प एक पर अधिक जानकारी के लिए, यह लिंक पर्याप्त होगा और विभिन्न झंडों की जानकारी होगी

संदर्भ: फ्लोटिंग पॉइंट नंबर को एक निश्चित परिशुद्धता में बदलें, और फिर स्ट्रिंग पर कॉपी करें


आप एक पूर्णांक का प्रतिनिधित्व कैसे करते हैं? यदि मैं "{i3}" का उपयोग करता हूं। प्रारूप (संख्या) मुझे एक त्रुटि मिलती है।
स्काइटक्स

यह मेरा मतलब है: यदि numvar=12.456, तो "{:.2f}".format(numvar)पैदावार 12.46लेकिन "{:2i}".format(numvar)एक त्रुटि देता है और मैं उम्मीद कर रहा हूं 12
स्काइटक्स


47

यहां किसी ने भी इसका उल्लेख नहीं किया है, इसलिए मुझे पायथन 3.6 के एफ-स्ट्रिंग / टेम्प्लेट-स्ट्रिंग प्रारूप में एक उदाहरण देना चाहिए, जो मुझे लगता है कि सुंदर रूप से साफ है:

>>> f'{a:.2f}'

यह लंबे उदाहरणों के साथ भी अच्छा काम करता है, परिचालकों के साथ और आवश्यकता नहीं है:

>>> print(f'Completed in {time.time() - start:.2f}s')

39

आप अजगर में 2 दशमलव स्थानों तक मूल्य को गोल करने के लिए प्रारूप ऑपरेटर का उपयोग कर सकते हैं :

print(format(14.4499923, '.2f')) // output is 14.45

4
यह रिटर्न स्ट्रिंग
Jemshit Iskenderov

29

पायथन 2.7 में:

a = 13.949999999999999
output = float("%0.2f"%a)
print output

1
यह बिल्कुल मदद नहीं करता है। outputके समान सटीक मान है a, इसलिए आपने अंतिम पंक्ति के print aबजाय लिखा हो सकता है print output
मार्क डिकिंसन

@MarkDickinson क्या आप फिर से कोशिश कर सकते हैं। क्योंकि यह मेरे कंपाइलर में उम्मीद के मुताबिक चल रहा है।
शशांक सिंह

1
आपको मेरी बात याद आ रही है। हां, आपका कोड प्रिंट करता है 13.95। लेकिन ऐसा करता है print a, aपायथन 2.7 में इस विशेष मूल्य के लिए , इसलिए यह वास्तव में स्पष्ट नहीं है कि प्रारूपण चरण का क्या मतलब था।
मार्क डिकिंसन

@MarkDickinson मैंने कोड संपादित किया है। मैं इस बात से सहमत हूं कि 'प्रिंट ए' प्रिंट मूल्य को "प्रिंट आउटपुट" के समान करता है। लेकिन अगर आप "a == आउटपुट" की तुलना करते हैं, तो परिणाम "गलत" होगा क्योंकि प्रारूपण चरण दो दशमलव बिंदुओं के लिए "a" फ्लोटिंग मान को राउंड ऑफ करता है।
शशांक सिंह

1
क्या आपने वास्तव में a == outputआपके द्वारा दिखाए गए कोड के लिए प्रयास किया था? यह Trueमेरे लिए देता है, और मुझे संदेह है कि यह आपके लिए भी है।
मार्क डिकिन्सन

22

पायथन ट्यूटोरियल में एक परिशिष्ट है जिसे फ्लोटिंग पॉइंट अरिथमेटिक कहा जाता है : मुद्दे और सीमाएं । इसे पढ़ें। यह बताता है कि क्या हो रहा है और क्यों पायथन अपना सर्वश्रेष्ठ प्रदर्शन कर रहा है। इसका एक उदाहरण और भी है जो आप से मेल खाता है। मुझे थोड़ा उद्धृत करें:

>>> 0.1
0.10000000000000001

हो सकता है कि आप round() फंक्शन का उपयोग करने के लिए इसे उसी अंदाज में काटें जो आपको उम्मीद है। लेकिन इससे कोई फर्क नहीं पड़ता:

>>> round(0.1, 1)
0.10000000000000001

समस्या यह है कि बाइनरी फ्लोटिंग-पॉइंट मूल्य के लिए संग्रहीत “0.1” पहले से ही सबसे अच्छा संभव बाइनरी सन्निकटन था1/10 , इसलिए इसे फिर से गोल करने की कोशिश करना बेहतर नहीं बना सकता है: यह पहले से ही उतना ही अच्छा था जितना कि यह हो जाता है।

एक और परिणाम यह है कि चूंकि 0.1 बिल्कुल नहीं है 1/10, दस मानों को 0.1सम्‍मिलित करें 1.0, बिलकुल नहीं।

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

आपकी समस्याओं का एक वैकल्पिक और समाधान decimalमॉड्यूल का उपयोग करना होगा ।


18

जैसा कि @Matt ने बताया, पायथन 3.6 एफ-स्ट्रिंग्स प्रदान करता है , और वे नेस्टेड मापदंडों का भी उपयोग कर सकते हैं :

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

जो प्रदर्शित करेगा result: 2.35



11

दशमलव वस्तु और गोल () विधि के संयोजन का उपयोग करें।

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')

7

पायथन और जावास्क्रिप्ट जैसी टाइप-डायनेमिक भाषाओं में फ़्लोटिंग पॉइंट को ठीक करने के लिए, मैं इस तकनीक का उपयोग करता हूं

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

आप निम्न के रूप में दशमलव का उपयोग भी कर सकते हैं:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')

1
getcontext().prec = 6केवल कार्यक्षेत्र या सभी स्थानों के लिए काम करता है?
जूलियो मैरिंस

1
अंकगणित अंकगणितीय परिचालनों के लिए वातावरण हैं। वे सटीक शासन करते हैं, गोलाई के लिए नियम निर्धारित करते हैं, यह निर्धारित करते हैं कि कौन से संकेत अपवाद के रूप में माने जाते हैं, और घातांक के लिए सीमा को सीमित करते हैं। प्रत्येक सूत्र का अपना वर्तमान संदर्भ @JulioMarins
Siamand

7
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

परिणाम:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'



4

यह 1,2,3 की तरह सरल है:

  1. दशमलव का उपयोग करेंतेजी से सही ढंग से गोल दशमलव अस्थायी बिंदु अंकगणित के लिए मॉड्यूल का :

    d = दशमलव (10000000.0000009)

गोलाई प्राप्त करने के लिए:

   d.quantize(Decimal('0.01'))

के साथ परिणाम होगा Decimal('10000000.00')

  1. DRY के ऊपर करें:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

या

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. इस उत्तर को बढ़ाएँ :)

पुनश्च: दूसरों की आलोचना: स्वरूपण गोल नहीं है।


2

किसी संख्या को किसी रिज़ॉल्यूशन में राउंड करने के लिए, सबसे अच्छा तरीका निम्नलिखित है, जो किसी भी रिज़ॉल्यूशन के साथ काम कर सकता है (0.01 दो दशमलव या अन्य चरणों के लिए):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0

अजगर 3.4.3 और सुन्न 1.9.1 पर मेरे लिए काम नहीं करता है? >>> एनपीपी के रूप में सुन्न आयात >>> Res = 0.01 >>> मूल्य = 0.184 >>> np.round (मूल्य / Res) * Res 0.17999999999999999
szeitlin

1
प्रलेखन की तलाश में मुझे लगता है कि समस्या numpy.roundसटीकता / सटीकता से आती है । इसलिए इसे रिज़ॉल्यूशन के साथ गुणा करने से पहले इसे परिभाषित करना होगा। मैंने कोड अपडेट किया। उसके लिये आपका धन्यवाद!
--बेलसी

केवल आवश्यक है numpy.float64np.round के परिणाम को floatया केवल उपयोग करने के लिए परिवर्तित करना round(value, 2)। कोई वैध IEEE 754 नंबर 13.949999999999999 (= 1395 / 100.) और 3.950000000000001 (= 1395 * .01) के बीच मौजूद है। आपको क्यों लगता है कि आपका तरीका सबसे अच्छा है? मूल मूल्य 13.949999999999999289 (= मान = दौर (मान, 2)) आपके 13.95000000000000178 (np.float96 द्वारा मुद्रित) से भी अधिक सटीक है। सुन्न के लिए भी अधिक जानकारी अब मेरे जवाब में जोड़ दी गई है कि आप शायद गलती से नीचे गए हैं। यह मूल रूप से सुन्न के बारे में नहीं था।
हाइनेसर

@hynekcer मुझे नहीं लगता कि मेरा जवाब सबसे अच्छा है। बस एक सीमा के उदाहरण को n दशमलव में जोड़ना चाहता था, लेकिन एक निर्धारित रिज़ॉल्यूशन के निकटतम। जैसा कि आपने कहा, मैंने जाँच की कि आप के बजाय @szeitlin उदाहरण के लिए intभी उपयोग कर सकते हैं float। आपकी अतिरिक्त टिप्पणी के लिए धन्यवाद। (क्षमा करें, लेकिन मैंने आपको
निराश

न्यूमेरिक प्रोसेसिंग (पांडा) के लिए पूरी नई निर्भरता जोड़ना "सबसे अच्छा तरीका" है?
हेजाज़मैन

1

lambda x, n: int (x * 10 n + .5) / 10 n ने कई वर्षों तक कई भाषाओं में मेरे लिए काम किया है ।


-13

मेरे द्वारा उपयोग की जाने वाली विधि स्ट्रिंग स्लाइसिंग है। यह अपेक्षाकृत जल्दी और सरल है।

सबसे पहले, फ्लोट को एक स्ट्रिंग में परिवर्तित करें, जिस लंबाई को आप चाहते हैं उसे चुनें।

float = str(float)[:5]

ऊपर एकल पंक्ति में, हमने मान को एक स्ट्रिंग में बदल दिया है, फिर स्ट्रिंग को केवल अपने पहले चार अंकों या वर्णों (समावेशी) में रखा है।

उम्मीद है की वो मदद करदे!


2
कृपया कई प्रश्नों के समान उत्तर न दें।
तिजोरी

18
वाह ... tdh ... कृपया कोई लेखांकन सॉफ्टवेयर कभी न बनाएं ... संख्या 113.94 होने पर क्या होता है ?? यह 113.9 में परिणाम देगा ... 0.04 लापता हो गया .... इसके अलावा पहले से ही 5 साल पहले के जवाब हैं ....
एंग्री 84
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.