Reputation: 3091
I wrote a function for rounding numbers to a certain number of digits on right side of dot. But I still don't understand how to properly define a scale to be used with quantize.
In the below example, res1
and res2
return the expected result. I found different examples for defining scale to have 2 numbers after the floating point. What is the difference between using "1.00" and "0.01"? Both seem to work the same way.
As for res3
when I pass a float to the Decimal constructor to get number_3 - ROUND_HALF_UP
doesn't seem to work there. Why does this happen? How should I define scale for Decimals created from float?
In case when I get floats as an input is the only way to get quantize work - first convert a float to a string?
from decimal import Decimal, ROUND_HALF_UP
def custom_round(dec: Decimal, scale, rounding_mode):
return dec.quantize(Decimal(scale), rounding_mode)
number_1 = Decimal("10.026")
res1 = custom_round(number_1, "1.00", ROUND_HALF_UP)
print(res1) # 10.03
number_2 = Decimal("28.525")
res2 = custom_round(number_2, "0.01", ROUND_HALF_UP)
print(res2) # 28.53
number_3 = Decimal(28.525)
res3 = custom_round(number_3, "0.01", ROUND_HALF_UP)
print(res3) # 28.52
Upvotes: 6
Views: 7155
Reputation: 77837
Your first two examples work the same way, because you gave them equivalent formats: two decimal places. You gave an input argument of a string, rather than a precision. YOu specified two decimals places of accuracy, and that's what you got. To specify accuracy, you give it a decimal value:
number_1 = Decimal("10.026")
res1 = custom_round(number_1, Decimal(1), ROUND_HALF_UP)
print(res1) # 10
number_2 = Decimal("28.525")
res2 = custom_round(number_2, Decimal(10)**-2, ROUND_HALF_UP)
print(res2) # 28.53
The third one works differently because you gave it an imprecise float
value that is not exactly 28.525. See Is floating-point math broken?.
Upvotes: 1
Reputation: 70582
There's no difference between "1.00" and "0.01" in this context. Unlike binary floating-point, decimal instances have a concept of significant trailing zeroes, and it's only the internal exponent quantize()
uses. Indeed,
>>> custom_round(Decimal("28.525"), "1234.56", ROUND_HALF_UP)
Decimal('28.53')
>>> custom_round(Decimal("28.525"), "000000.00", ROUND_HALF_UP)
Decimal('28.53')
also work the same way.
For your other question, look at what number_3
converts to:
>>> number_3
Decimal('28.52499999999999857891452847979962825775146484375')
float->decimal conversion is exact, and the float literal 28.525 is represented internally by a binary float that only approximates the decimal 28.525 (which cannot be represented exactly as a binary float - you get the closest possible binary approximation instead). The exact decimal value of that binary approximation is - as shown - a ilttle bit less than the decimal 28.525. That's why it rounds down.
Upvotes: 4