Round an answer to 2 decimal places in Python
Asked Answered
R

5

12

The issue i am having is my rounding my results to 2 decimal places. My app gets the right results, however, i am having difficulty making the app round to the nearest decimal as you would with currency

cost = input("\nEnter the 12 month cost of the Order: ")
cost = float(cost)

print("\n12 Month Cost:",
  cost * 1,"USD")
print("6 Month Cost:",
  cost * 0.60,"USD")
print("3 Month Cost:",
  cost * 0.36,"USD")

so for example if the 12 month price is $23, the 6 month price is 13.799999999999999 but i want it to show 13.80

I've looked around google and how to round a number but couldn't find much help on rounding a result.

Ratty answered 19/11, 2012 at 22:34 Comment(4)
Just a point about your multipliers for 12 Month, 6 Month and 3 Month costs... I think these should be 1, 0.5 and 0.25 instead of 1, 0.6 and 0.36. You are taking 50% of 12 months (6 months) and 25% of 12 months (3 months).Tearful
@Tearful It's possible that the OP is writing a subscription system that gives the best discounts based on the length of time subscribed. Subscribe for six months for $13.80, but subscribing for twelve months is $4.60 cheaper over the cost of the year!Boulanger
@Boulanger ... excellent point! I do a lot of math/science data processing. Embarrassing assumption on my part.Tearful
@Tearful Don't worry, I had the same thought you did until I saw that you had already written it... only after you wrote your comment did I come up with the exception; I'm sure that if we arrived in different order, our positions might have been reversed.Boulanger
P
15

You should use a format specifier:

print("6 Month Cost: %.2fUSD" % (cost * .6))

Even better, you shouldn't rely on floating point numbers at all and use the decimal module instead, which gives you arbitrary precision and much more control over the rounding method:

from decimal import Decimal, ROUND_HALF_UP
def round_decimal(x):
  return x.quantize(Decimal(".01"), rounding=ROUND_HALF_UP)

cost = Decimal(input("Enter 12 month cost: "))
print("6 Month Cost: ", round_decimal(cost * Decimal(".6")))
Prent answered 19/11, 2012 at 22:39 Comment(1)
Taking this beyond currency formats, wouldn't it generally have better performance if we used a format specifier on regular Python decimal numbers than to use the decimal module?Nonperishable
J
3

A classic way is to multiply by 100, add 0.5 (this is to round) and int() the result. Now you have the number of rounded cents, divide by 100 again to get back the rounded float.

cost = 5.5566
cost *= 100 # cost = 555.66
cost += 0.5 # cost = 556.16
cost = int(cost) # cost = 556
cost /= float(100) # cost =  5.56

cost = 5.4444
cost = int(( cost * 100 ) + 0.5) / float(100) # cost = 5.44
Juliajulian answered 19/11, 2012 at 22:37 Comment(1)
Why people prefer Decimal to this method?Manado
F
2

If you just want to have it as a string, format can help:

format(cost, '.2f')

This function returns a string that is formated as defined in the second parameter. So if cost contains 3.1418 the code above returns the string '3.14'.

Frisket answered 10/9, 2013 at 21:12 Comment(0)
R
1

If you just want it to print, string formatting will work:

print("\n12 Month Cost:%.2f USD"%(cost*1))
Rubbery answered 19/11, 2012 at 22:40 Comment(0)
M
0

In some countries cents are allowed to be only multiple of 5. So, f{money:.2f'} just cuts the extra digits but a further rounding process to the nearest multiple of 5 is needed.

For instance 1.233333 will be formatted to 1.23 and then rounded to the closest multiple of 5, 1.25. Or, 1.27 will become 1.25.

Here my solution based on string manipulation

def cround(x:float) -> float:
    """Currency rounder"""
    # round to 2 decimal places
    s = f"{x:.2f}"
    # round to 5 or 0 cent
    i, dot, d = s.partition('.')
    d1, d2 = d
    # check last digit
    if d2 in "05": #    stay the same
        return float(s)
    elif d2 in "12": #  round down
        d = d1 + "0"
    elif d2 in "67": #  round down
        d = d1 + "5"
    elif d2 in "34": #  round up
        d = d1 + "5"
    elif d2 in "89": #  round up
        d2 = "0"
        if int(d1) + 1 < 9:
            d = str(int(d1) + 1) + '0'
        else:
            d = '00'
            i = str(int(i) + 1)      
      
    return float(''.join([i, dot, d]))


# test
ms     = [1.62, 1.63, 1.67, 1.68, 2.1, 2.111, 2.119, 2.138]
ms_res = [1.60, 1.65, 1.65, 1.70, 2.1, 2.100, 2.100, 2.150] # expected rounded values

# result
for m, m_true in zip(ms, ms_res):
    print(m, cround(m), cround(m) == m_true)

Output

1.62 1.6 True
1.63 1.65 True
1.67 1.65 True
1.68 1.7 True
2.1 2.1 True
2.111 2.1 True
2.119 2.1 True
2.138 2.15 True
Myeshamyhre answered 15/6, 2023 at 9:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.