Drijvers beperken tot twee decimalen

Ik wil dat a wordt afgerond op 13,95.

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

De functie round werkt niet werken zoals ik had verwacht.


Antwoord 1, autoriteit 100%

Je loopt tegen het oude probleem aan met getallen met drijvende komma dat niet alle getallen kunnen worden weergegeven precies. De opdrachtregel toont u alleen de volledige drijvende-kommavorm uit het geheugen.

Bij drijvende-kommaweergave is uw afgeronde versie hetzelfde getal. Aangezien computers binair zijn, slaan ze getallen met drijvende komma op als een geheel getal en delen ze vervolgens door een macht van twee, zodat 13,95 op dezelfde manier wordt weergegeven als 125650429603636838/(2**53).

Getallen met dubbele precisie hebben een nauwkeurigheid van 53 bits (16 cijfers) en gewone floats hebben een nauwkeurigheid van 24 bits (8 cijfers). Het floating point type in Python gebruikt dubbele precisie om de waarden op te slaan.

Bijvoorbeeld

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

Als je na slechts twee decimalen komt (om bijvoorbeeld een valutawaarde weer te geven), dan heb je een paar betere keuzes:

  1. Gebruik gehele getallen en sla waarden op in centen, niet in dollars, en deel deze vervolgens door 100 om te converteren naar dollars.
  2. Of gebruik een vast puntgetal, zoals decimaal.

Antwoord 2, autoriteit 35%

Er zijn nieuwe formaatspecificaties, Stringformaatspecificatie Minitaal:

Je kunt hetzelfde doen als:

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

Opmerking 1: het bovenstaande retourneert een tekenreeks. Om als float te krijgen, wikkel je eenvoudig met float(...):

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

Opmerking 2: inpakken met float() verandert niets:

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

Antwoord 3, autoriteit 18%

De ingebouwde round() werkt prima in Python 2.7 of hoger.

Voorbeeld:

>>> round(14.22222223, 2)
14.22

Bekijk de documentatie.


Antwoord 4, autoriteit 8%

Ik denk dat de eenvoudigste aanpak is om de functie format() te gebruiken.

Bijvoorbeeld:

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

Dit levert een zwevend getal op als een tekenreeks die is afgerond op twee decimalen.


Antwoord 5, autoriteit 7%

Niemand hier lijkt het nog te hebben genoemd, dus laat me een voorbeeld geven in het f-string/template-string-formaat van Python 3.6, wat ik mooi netjes vind:

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

Het werkt ook goed met langere voorbeelden, met operators en zonder haakjes:

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

Antwoord 6, autoriteit 5%

De meeste getallen kunnen niet exact worden weergegeven in floats. Als u het getal wilt afronden omdat dat is wat uw wiskundige formule of algoritme vereist, dan wilt u rond gebruiken. Als je de weergave alleen tot een bepaalde precisie wilt beperken, gebruik dan niet eens rond en formatteer het gewoon als die string. (Als je het wilt weergeven met een alternatieve afrondingsmethode, en er zijn tonnen, dan moet je de twee benaderingen mengen.)

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

En als laatste, hoewel misschien wel het belangrijkste, als je exacte wiskunde wilt, dan wil je helemaal geen floats. Het gebruikelijke voorbeeld is omgaan met geld en het opslaan van ‘centen’ als een geheel getal.


Antwoord 7, autoriteit 5%

Gebruik

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

in plaats van

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

Omdat dit laatste kan leiden tot uitvoerfouten bij het uitvoeren van meerdere variabelen (zie opmerkingen).


Antwoord 8, autoriteit 3%

Probeer de onderstaande code:

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

Antwoord 9, autoriteit 3%

TLDR 😉

Het afrondingsprobleem van invoer/uitvoer is definitief opgelost door Python 2.7.0 en 3.1.

Een correct afgerond getal kan omkeerbaar heen en weer worden geconverteerd:
str -> float() -> repr() -> float() ... of Decimal -> float -> str -> Decimal
Een decimale type is niet meer nodig voor opslag.


(Natuurlijk kan het nodig zijn om een ​​resultaat van het optellen of aftrekken van afgeronde getallen af ​​te ronden om de geaccumuleerde laatste bit-fouten te elimineren. Een expliciete decimale rekenkunde kan nog steeds handig zijn, maar een conversie naar string door str() (dat wil zeggen met afronding op 12 geldige cijfers) is meestal goed genoeg als er geen extreme nauwkeurigheid of geen extreem aantal opeenvolgende rekenkundige bewerkingen vereist is.)

Oneindige test:

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+ :-)

Documentatie

Zie de Release-opmerkingen Python 2.7 – Andere taalwijzigingen de vierde alinea:

Conversies tussen getallen met drijvende komma en tekenreeksen worden nu op de meeste platforms correct afgerond. Deze conversies komen op veel verschillende plaatsen voor: str() op floats en complexe getallen; de float en complexe constructeurs; numerieke opmaak; het serialiseren en de-serialiseren van floats en complexe getallen met behulp van de modules marshal, pickle en json; ontleden van float en denkbeeldige literals in Python-code; en decimaal-naar-zwevend conversie.

Hieraan gerelateerd, retourneert de repr() van een getal met drijvende komma x nu een resultaat op basis van de kortste decimale tekenreeks die gegarandeerd terug naar x wordt afgerond onder de juiste afronding (met afrondingsmodus rond-half-naar-even). Voorheen gaf het een string op basis van het afronden van x op 17 decimale cijfers.

Het gerelateerde probleem


Meer informatie: De opmaak van float vóór Python 2.7 was vergelijkbaar met de huidige numpy.float64. Beide typen gebruiken dezelfde 64-bits IEEE 754 dubbele precisie met 52-bits mantisse. Een groot verschil is dat np.float64.__repr__ vaak wordt geformatteerd met een buitensporig decimaal getal zodat er geen bit verloren kan gaan, maar er bestaat geen geldig IEEE 754-nummer tussen 13.94999999999999 en 13.950000000000001. Het resultaat is niet mooi en de conversie repr(float(number_as_string)) is niet omkeerbaar met numpy. Aan de andere kant: float.__repr__ is zo opgemaakt dat elk cijfer belangrijk is; de volgorde is zonder gaten en de conversie is omkeerbaar. Simpel: als je misschien een numpy.float64-nummer hebt, converteer het dan naar normaal float om te worden geformatteerd voor mensen, niet voor numerieke processors, anders is er niets meer nodig met Python 2.7+.


Antwoord 10, autoriteit 3%

U kunt het uitvoerformaat wijzigen:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95

Antwoord 11, autoriteit 3%

Met Python < 3 (bijv. 2.6 of 2.7), zijn er twee manieren om dit te doen.

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

Maar houd er rekening mee dat voor Python-versies boven 3 (bijv. 3.2 of 3.3), optie twee voorkeur.

Voor meer informatie over optie twee raad ik deze link aan over stringopmaak van de Python-documentatie.

En voor meer informatie over optie één, deze link is voldoende en heeft informatie over de verschillende vlaggen.

Referentie: drijvend converteren verwijs nummer naar een bepaalde precisie en kopieer vervolgens naar string


Antwoord 12, autoriteit 2%

U kunt de operator format gebruiken om de waarde in python tot op 2 decimalen af ​​te ronden:

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

Antwoord 13, autoriteit 2%

float_number = 12.234325335563
round(float_number, 2)

Dit komt terug;

12.23

Uitleg:

afrondfunctie heeft twee argumenten;
Getal dat moet worden afgerond en het aantal decimalen dat moet worden geretourneerd. Hier heb ik 2 decimalen geretourneerd.


Antwoord 14, autoriteit 2%

In Python 2.7:

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

Antwoord 15

Zoals @Matt opmerkte, Python 3.6 biedt f-strings, en ze kunnen ook geneste parameters:

value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')

die result: 2.35


Antwoord 16

De Python-tutorial heeft een appendix genaamd Floating Point Rekenkunde: problemen en beperkingen. Lees het. Het legt uit wat er gebeurt en waarom Python zijn best doet. Het heeft zelfs een voorbeeld dat overeenkomt met het uwe. Laat me een beetje citeren:

>>> 0.1
0.10000000000000001

je komt misschien in de verleiding om de round() . te gebruiken
functie om het terug te hakken naar de single
cijfer dat u verwacht. Maar dat maakt niet uit
verschil:

>>> round(0.1, 1)
0.10000000000000001

Het probleem is dat het binaire
drijvende-kommawaarde opgeslagen voor “0.1”
was al de best mogelijke binaire
benadering tot 1/10, dus probeer
er nog een keer omheen kan het niet beter maken:
het was al zo goed als maar kan.

Een ander gevolg is dat sinds 0.1
is niet precies 1/10, tien optellend
waarden van 0.1 leveren mogelijk niet precies op
1.0, ofwel:

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

Een alternatief en oplossing voor uw problemen is het gebruik van de decimal-module.


Antwoord 17

We hebben meerdere opties om dat te doen:
Optie 1:

x = 1.090675765757
g = float("{:.2f}".format(x))
print(g)

Optie 2:
De ingebouwde round() ondersteunt Python 2.7 of hoger.

x = 1.090675765757
g =  round(x, 2)
print(g)

Antwoord 18

Gebruik een combinatie van Decimaal object en round() methode.

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

Antwoord 19

Het doet precies wat je het zei te doen en werkt correct. Lees meer over floating point-verwarring en probeer misschien decimale objecten in plaats daarvan.


Antwoord 20

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)

Resultaten:

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'

Antwoord 21

Voor het corrigeren van de drijvende komma in typedynamische talen zoals Python en JavaScript, gebruik ik deze techniek

# 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

U kunt decimaal ook als volgt gebruiken:

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

Antwoord 22

Hoe zit het met een lambda-functie zoals deze:

arred = lambda x,n : x*(10**n)//1/(10**n)

Op deze manier zou je gewoon kunnen doen:

arred(3.141591657,2)

en krijg

3.14

Antwoord 23

orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54


Antwoord 24

Het is simpel, zoals 1,2,3:

  1. gebruik decimaal module voor snelle correct afgeronde decimale drijvende komma rekenkunde:

    d=Decimaal (10000000.0000009)

om afronding te bereiken:

   d.quantize(Decimal('0.01'))

resultaten met Decimal('10000000.00')

  1. maak hierboven DRY:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OF

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. upvote dit antwoord 🙂

PS: kritiek van anderen: opmaak is niet afronden.


Antwoord 25

Om een ​​getal naar een resolutie af te ronden, is de beste manier de volgende, die met elke resolutie kan werken (0,01 voor twee decimalen of zelfs andere stappen):

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

Antwoord 26

De antwoorden die ik zag werkten niet met het geval float (52.15). Na wat testen is er de oplossing die ik gebruik:

import decimal
def value_to_decimal(value, decimal_places):
    decimal.getcontext().rounding = decimal.ROUND_HALF_UP  # define rounding method
    return decimal.Decimal(str(float(value))).quantize(decimal.Decimal('1e-{}'.format(decimal_places)))

(De conversie van de ‘waarde’ naar float en dan string is erg belangrijk, op die manier kan ‘value’ van het type float, decimaal, integer of string zijn!)

Ik hoop dat dit iemand helpt.


Antwoord 27

lambda x,n:int(x*10n+.5)/10n heeft vele jaren voor mij gewerkt in vele talen.


Antwoord 28

Als je met geld wilt omgaan, gebruik dan de python decimaal-module

from decimal import Decimal, ROUND_HALF_UP
# amount can be integer, string, tuple, float, or another Decimal object
def to_money(amount) -> Decimal:
    money = Decimal(amount).quantize(Decimal('.00'), rounding=ROUND_HALF_UP)
    return money

Antwoord 29

Hier is de eenvoudige oplossing met de formaatfunctie.

float(format(num, '.2f'))

OPMERKING: we converteren getallen naar zwevend omdat de formaatmethode is
terugkerende tekenreeks.


Antwoord 30

De methode die ik gebruik is die van string slicing. Het is relatief snel en eenvoudig.

Converteer eerst de float naar een string en kies vervolgens de lengte die je wilt hebben.

float = str(float)[:5]

In de enkele regel hierboven hebben we de waarde geconverteerd naar een tekenreeks en vervolgens de tekenreeks behouden tot de eerste vier cijfers of tekens (inclusief).

Hopelijk helpt dat!

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes