-1

I have a beginner problem. How can I round up to 2 decimal? Here is what I tried and what I want to achieve:

import math

var_1 = 14.063  # expected = 14.06
var_2 = 10.625  # expected = 10.63

print(round(14.063, 2))
print(round(10.625, 2))


print('===========================')


def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier


print(round_up(var_1, 2))
print(round_up(var_2, 2))

And the Output is:

14.06 
10.62  
===========================
14.07
10.63

So neither of those wroks for me...

bbfl
  • 277
  • 1
  • 2
  • 16
  • Why do you expect `10.625` to round to `10.63`? The [documentation](https://docs.python.org/3/library/functions.html#round) states quite clearly that numbers are rounded towards the even side – Pranav Hosangadi Mar 30 '22 at 15:34
  • 3
    Your title says you want to round *up*, but var_1 = 14.063 rounds *up* to 14.07. Why would you expect 14.06? – user2357112 Mar 30 '22 at 15:35
  • This is not "a beginner problem" :) – Zach Young Mar 30 '22 at 16:08
  • @user2357112supportsMonica, how did you interpret this question? I saw it as "I want 2 decimal places, and if I'm over 2 decimals places, round up if the 3rd decimal is 5 or greater". This seems to be a well-documented way to round, albeit biased and error-prone: https://en.wikipedia.org/wiki/Rounding#Round_half_up, https://stackoverflow.com/questions/45083399. – Zach Young Mar 30 '22 at 16:39
  • I want to round up, I don't look for answer why it does not work that way. Sorry, I know 'expect' in the comments looks confusing. – bbfl Mar 30 '22 at 18:56

4 Answers4

2

The Decimal class, quantize() method, and ROUND_HALF_UP rule from the decimal module can handle this:

from decimal import Decimal, ROUND_HALF_UP

var_1 = 14.063  # expected = 14.06
var_2 = 10.625  # expected = 10.63

# a Decimal object with an explicit exponent attribute/property (to be interpreted by quantize)
Two_places = Decimal("1e-2")

for var in [var_1, var_2]:
    rounded = Decimal(var).quantize(Two_places, rounding=ROUND_HALF_UP)
    print(f"decimal: {rounded}")
    print(f"float:   {float(rounded)}")

and I get:

decimal: 14.06
float:   14.06
decimal: 10.63
float:   10.63

Keep in mind that when you're dealing with floats, you're always manipulating a less-than-precise representation of what you probably (naturally) have in mind:

Decimal(1.65)    # Decimal('1.649999999999999911182158029987476766109466552734375')
Decimal('1.65')  # Decimal('1.65')

In the first case, 1.65 was first turned into an IEEE-754 float, which has precision errors going from base-10 to base-2, then passed to Decimal. In the second case, Decimal interpreted the number as "one, and 65 100-ths" which equates to "165 times 10 raised to the minus 2", or 165e-2.

Zach Young
  • 10,137
  • 4
  • 32
  • 53
1

this should work, although there is probebly a more efficient way of doing it. I just took your code and determined which one was closer, and if they are the same to round up.
Edit: It seems that PCM has made such version.

import math
decimals = 2
var_1 = 14.063
var_2 = 10.625

var_1down = round(var_1, decimals)
var_2down = round(var_2, decimals)

def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier

var_1up = round_up(var_1, decimals)
var_2up = round_up(var_2, decimals)

if var_1 - var_1down >= var_1up - var_1:
    var_1round = var_1up
else:
    var_1round = var_1down

if var_2 - var_2down >= var_2up - var_2:
    var_2round = var_2up
else:
    var_2round = var_2down

print (var_1round)
print (var_2round)
Blazing Blast
  • 101
  • 11
1

Try this. This finds the nearest one and if not, then round up -

import math
v1 = 14.063
v2 = 10.625

def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    var_down = round(n, 2)
    var_up = math.ceil(n * multiplier) / multiplier

    if n - var_down >= var_up - n:
        return var_up

    else:
        return var_down

v1_round = round_up(v1, 2)
v2_round = round_up(v2, 2)

print (v1_round) # 14.06
print (v2_round) # 10.63
PCM
  • 2,881
  • 2
  • 8
  • 30
-2

If you check the docs you will see that "values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2)".

So 10.625 rounds to 10.62. You may try adding a very small value, e.g. 0.00001, but even so, since the way float numbers work, you may have some surprise in a few cases.

gimix
  • 3,431
  • 2
  • 5
  • 21
  • 1
    According to me, this doesn't answer the question. I think it would be better if u had put this down as a comment (along with a link to the docs mentioning this) – PCM Mar 30 '22 at 15:38
  • You're right about the link to the docs, but why it is not an answer? The OP is asking for something that cannot be done in Python (at least not in a straightforward way), so the answer is "you cannot" – gimix Mar 30 '22 at 15:44