-1

When converting to float or decimal, the values are not correct. Below are some examples:

"{0:.20f}".format(0.1) = '0.10000000000000000555'
"{0:.20f}".format(1/3) = '0.33333333333333331483'
Decimal(2.4) = Decimal('2.399999999999999911182158029987476766109466552734375')

The above behavior is causing problems when rounding numbers. e.g. I expect round(6.345, 2) to be equal to 6.35, but it comes out to be 6.34, probably because Decimal(6.345) evaluates to 6.34499999999999975131004248396493494510650634765625, which is closer to 6.34, than 6.35.

Why does this happen? What is the work-around for this?

2 Answers2

0

I dont know if this is what you are looking for, but you can write your own round function that does the round procedure as you want it. Here is an example, probably not my best work and there are for sure more pythonic ways, but it is at least something you can build up on:

num = 6.345

def custom_round(number, spaces=0):
    if isinstance(num, int):
        return num

    integer, decimal = str(number).split('.')

    if spaces >= len(decimal):
        return num
    elif spaces == 0:
        if int(decimal[:1]) >= 5:
            return int(integer) + 1
        else:
            return int(integer)
    elif int(decimal[spaces : spaces + 1]) >= 5:
        return float(integer + "." + str(int(decimal[:spaces]) + 1))
    else:
        return float(integer  + "." + str(int(decimal[:spaces])))

print(custom_round(num, 1))
# 6.3
print(custom_round(num, 2))
# 6.35
MisterNox
  • 1,445
  • 2
  • 8
  • 22
0

This could possibly be a workaround.

import math
from decimal import Decimal
print("{0:.20f}".format(0.1))
print("{0:.20f}".format(1/3))

def round_half_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.floor(n*multiplier + 0.5) / multiplier
num=6.345

print(round(Decimal(str(num)),2))
print(round_half_up(num,2))

Output:

0.10000000000000000555                                                                                                  
0.33333333333333331483                                                                                                  
6.34                                                                                                                    
6.35

Reference: https://realpython.com/python-rounding/#rounding-half-up

If this does not meet your needs, then I would suggest going with fractions, like instead of having a=6.345, you can instead have a=[6345,1000] or just a=[6345,3] (3 meaning 1o^3) and calculate the floating-point value of the answer at the last. But then you will have to manually make functions for all arithmetic operations you perform.

Here is an answer which suggests the use of fractions.Fraction https://stackoverflow.com/a/53821658/11474769

I do not have any experience with it, but the from the docs it seems that it can prove useful in this case. Link to fractions.Fraction doc https://docs.python.org/3/library/fractions.html

Please do have a look at it.

Dharman
  • 30,962
  • 25
  • 85
  • 135
ubaid shaikh
  • 453
  • 3
  • 7