Jak zaokrąglić liczbę zmiennoprzecinkową do określonego miejsca dziesiętnego?

84

Załóżmy, że mam 8.8333333333333339i chcę go przekonwertować na 8.84. Jak mogę to osiągnąć w Pythonie?

round(8.8333333333333339, 2)daje 8.83i nie 8.84. Jestem nowy w Pythonie lub ogólnie w programowaniu.

Nie chcę drukować tego jako ciągu, a wynik będzie dalej używany. Aby uzyskać więcej informacji na temat problemu, zapoznaj się z poradami Tima Wilsona dotyczącymi programowania w języku Python: Kalkulator pożyczki i płatności .

hsinxh
źródło
4
runda (8,8333333333333339, 2) da 8,83 nigdy 8,84, jak się wydaje.
VGE
42
Dlaczego 8,84? 8,8333333 ... należy zaokrąglić do 8,83, dążąc do dwóch miejsc po przecinku.
Tim Pietzcker
1
jeśli chcesz wydrukować wartość, użyj formatu, takiego jak print "% .2f"% 8.8333333333333339. spowoduje to wydrukowanie wartości z 2 cyframi
VGE
Zmieniłem tytuł, ponieważ pojawia się jako wczesny wynik dla „okrągłego pływaka w języku Python” i prawdopodobnie nie jest tym, czego szuka większość ludzi. Miejmy nadzieję, że nowy tytuł wyjaśni sprawę.
jpmc26

Odpowiedzi:

101

8.833333333339(lub 8.833333333333334wynik 106.00/12) prawidłowo zaokrąglony do dwóch miejsc po przecinku to 8.83. Matematycznie wygląda na to, że to, czego chcesz, to funkcja sufitu . Ten w mathmodule Pythona nosi nazwę ceil:

import math

v = 8.8333333333333339
print(math.ceil(v*100)/100)  # -> 8.84

Respectively, the floor and ceiling functions generally map a real number to the largest previous or smallest following integer which has zero decimal places — so to use them for 2 decimal places the number is first multiplied by 102 (or 100) to shift the decimal point and is then divided by it afterwards to compensate.

If you don't want to use the math module for some reason, you can use this (minimally tested) implementation I just wrote:

def ceiling(x):
    n = int(x)
    return n if n-1 < x <= n else n+1

How all this relates to the linked Loan and payment calculator problem:

screenshot of loan calculator output

From the sample output it appears that they rounded up the monthly payment, which is what many call the effect of the ceiling function. This means that each month a little more than 112 of the total amount is being paid. That made the final payment a little smaller than usual — leaving a remaining unpaid balance of only 8.76.

It would have been equally valid to use normal rounding producing a monthly payment of 8.83 and a slightly higher final payment of 8.87. However, in the real world people generally don't like to have their payments go up, so rounding up each payment is the common practice — it also returns the money to the lender more quickly.

martineau
źródło
67

This is normal (and has nothing to do with Python) because 8.83 cannot be represented exactly as a binary float, just as 1/3 cannot be represented exactly in decimal (0.333333... ad infinitum).

If you want to ensure absolute precision, you need the decimal module:

>>> import decimal
>>> a = decimal.Decimal("8.833333333339")
>>> print(round(a,2))
8.83
Tim Pietzcker
źródło
Not if you use the print function/statement (depending on your Python version).
Tim Pietzcker
>>> 106.00/12 => 8.833333333333334
martineau
22

You want to use the decimal module but you also need to specify the rounding mode. Here's an example:

>>> import decimal
>>> decimal.Decimal('8.333333').quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_UP)
Decimal('8.34')
>>> decimal.Decimal('8.333333').quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_DOWN)
Decimal('8.33')
>>> 
casevh
źródło
13

A much simpler way is to simply use the round() function. Here is an example.

total_price = float()
price_1 = 2.99
price_2 = 0.99
total_price = price_1 + price_2

If you were to print out total_price right now you would get

3.9800000000000004

But if you enclose it in a round() function like so

print(round(total_price,2))

The output equals

3.98

The round() function works by accepting two parameters. The first is the number you want to round. The second is the number of decimal places to round to.

user2252471
źródło
7

If you round 8.8333333333339 to 2 decimals, the correct answer is 8.83, not 8.84. The reason you got 8.83000000001 is because 8.83 is a number that cannot be correctly reprecented in binary, and it gives you the closest one. If you want to print it without all the zeros, do as VGE says:

print "%.2f" % 8.833333333339   #(Replace number with the variable?)
Andreas Løve Selvik
źródło
6

The easiest way to do this is by using the below function, which is built in:

format()

For example:

format(1.242563,".2f")

The output would be:

1.24

Similarly:

format(9.165654,".1f")

would give:

9.2
sai surya madhav
źródło
The format answer was given in 2010 here. You could have updated that answer instead.
ZF007
5

If you want to round, 8.84 is the incorrect answer. 8.833333333333 rounded is 8.83 not 8.84. If you want to always round up, then you can use math.ceil. Do both in a combination with string formatting, because rounding a float number itself doesn't make sense.

"%.2f" % (math.ceil(x * 100) / 100)
Rosh Oxymoron
źródło
4

Just for the record. You could do it this way:

def roundno(no):
    return int(no//1 + ((no%1)/0.5)//1)

There, no need for includes/imports

twohot
źródło
2

Here is my solution for the round up/down problem

< .5  round down

> = .5  round up

import math

def _should_round_down(val: float):
    if val < 0:
        return ((val * -1) % 1) < 0.5
    return (val % 1) < 0.5

def _round(val: float, ndigits=0):
    if ndigits > 0:
        val *= 10 ** (ndigits - 1)
    is_positive = val > 0
    tmp_val = val
    if not is_positive:
        tmp_val *= -1
    rounded_value = math.floor(tmp_val) if _should_round_down(val) else math.ceil(tmp_val)
    if not is_positive:
        rounded_value *= -1
    if ndigits > 0:
        rounded_value /= 10 ** (ndigits - 1)
    return rounded_value

# test
# nr = 12.2548
# for digit in range(0, 4):
#     print("{} decimals : {} -> {}".format(digit, nr, _round(nr, digit)))

# output
# 0 decimals : 12.2548 -> 12
# 1 decimals : 12.2548 -> 12.0
# 2 decimals : 12.2548 -> 12.3
# 3 decimals : 12.2548 -> 12.25
opra
źródło
1

I have this code:

tax = (tax / 100) * price

and then this code:

tax = round((tax / 100) * price, 2)

round worked for me

Nic56
źródło
You solved my problem. I could only round with this. Nothing else worked. renewal_percentage=round(df_x_renewal_count/df_all_count*100)
Kierk
0

Here is a simple function to do this for you:

def precision(num,x):
    return "{0:.xf}".format(round(num))

Here, num is the decimal number. x is the decimal up to where you want to round a floating number.

The advantage over other implementation is that it can fill zeros at the right end of the decimal to make a deciaml number up to x decimal places.

Example 1:

precision(10.2, 9)

will return

10.200000000 (up to 9 decimal points)

Example 2:

precision(10.2231, 2)

will return

10.22 (up to two decimal points)

Akash Kandpal
źródło