Python Decimal Calculation Is Not Precise - python

The result of 1 / 9 * 9 should equal 1. However, Python returns 0.99999999999...
from decimal import Decimal
import decimal
decimal.getcontext().rounding = decimal.ROUND_HALF_UP
decimal.getcontext().prec = 256
dec1 = Decimal('1')
dec9 = Decimal('9')
dec_result = dec1 / dec9 * dec9
print(type(dec_result))
print(dec_result)
I need a precise method for calculations,; hence, the usage of decimal vs. float.
Can anybody suggest a fix? Thanks...

explanation of why this happens:
This is not a precession error from python's decimal module.
Many calculating machines and many other programming languages behave the same way. Grab an old calculator, divide 1 by 9 and multiply it again by 9. You'll get the 0.9999999 that you got from python.
We, as humans can determine that the exact result is equal to one by simplifying the fraction 1 * 9 / 9 = 1. But many digital calculating machines calculate the operation by going through each element one by one, basically dividing the operation into smaller operations. So for a computer, 1 / 9 * 9 is going to be like this: Calculate 1 divided by 9. Multiply the result by 9. If you do the calculation by hand, going through each sub-operation one by one, you'll get the same result.
However: Even though from my perspective, 0.9999999 result is much accurate, many modern calculators and many modern programming languages such as Python, JS, Java, C++ and even C handles this problem with their primitive data types. That mean's that if you are using primitive data types of those programming languages, double and float, you don't need to worry about this sort of precession problems. I tested both JS and Python and got similar results.
Python 3.8
>>> a = 1.0
>>> b = 9.0
>>> a / b * b
1.0

It seems like the problem of accuracy is within the Decimal module itself
Normally doing this operation
1/9 * 9
Will give us the result as 1.0
I Recomend You To Go With The Normal Division Itself

Related

How to ensure expressions that evaluate to floats, give the expected integer value with int(*)

In this question's most general form, I want to know how I can guarantee that int(x * y) (with x and y both being floats gives me the arithmetically "correct" answer when I know the result to be a round number. For example: 1.5 * 2.0 = 3, or 16.0 / 2.0 = 8. I worry this could be a problem because int can round down if there is some floating point error. For example: int(16.0 - 5 * sys.float_info.epsilon) gives 15.
And specializing the question a bit, I could also ask about division between two ints where I know the result is a round number. For example 16 / 2 = 8. If this specialization changes the answer to the more general question, I'd like to know how.
By the way, I know that I could do int(round(x * y). I'm just wondering if there's a more direct built-in, or if there's some proven guarantee that means I don't have to worry about this in the first place.
If both inputs are exact, and the mathematically correct result is representable, then the output is also guaranteed to be exact. This is only true for a limited number of basic floating-point operations, but * and / are such operations.
Note that the "both inputs are exact" condition is only satisfiable for dyadic rationals. Numbers like 1.5 are fine, but numbers like 0.1 cannot be exactly represented in binary floating point. Also, floating point precision limits apply to integers, too, not just fractional values - very large integers may not be exactly representable, due to requiring more precision than a Python float has.

Which stage to round at?

In Python, at what stage should round be used? Take this example: 10 * math.log(x) + 10 If I want this to be rounded which should I use?
round(10 * math.log(x) + 5)
round(10 * math.log(x)) + 5
10 * round(math.log(x)) + 5
My guess would be that rounding early would run the fastest because more arithmetic happens with integers, which seem like they should be faster than floats. Rounding seems less likely to break if some later values change.
Would the answer be the same with int()?
Don't prematurely optimize. In many cases, it's not highly optimized mathematical functions which slow down programs, but the logic, structure or data types used in the calculation.
To that end, I recommend you use cProfile to identify bottlenecks. Note that cProfile itself has an overhead, so it is mostly useful for relative comparisons.
As per #glibdud's comment, you have to understand how rounding will affect your calculation. Try a few examples, or perform a test to see how your error may vary across a large number of inputs.
The earlier you are rounding, the more your result will be affected by this rounding. In my opinion, it all depends on the expectations of your program.
As for the difference between int() and round(), this thread answers it perfectly.
To be more specific to your question about performance : The round() function, that is a python built-in, is implemented in C, and you shouldn't really worry about performance as it will be very, very negligible.
Round function
That entirely depends upon how you want your answer to be formatted and interpreted. I would not be hung up on the speed of the round function though (unless the very minor performance gain is crucial to your program). I would think about what I'm trying to accomplish by rounding. If your goal is to produce an output that is rounded to the nearest integer (for simplicity) then I would encompass your entire arithmetic statement into the round function. If your goal is to only use rounded integers in your log calculations (maybe because you don't want to use floats) then you should only round the math.log(x) function. There is no technical reason why you would use either, but there is definitely a logical reason that you would want to choose either of your options.
Please note that the Python Math.log() function is the base of e by default. By your questions it's unclear what base you expect so I'll assume log base of 10 like Google does. In order to make it equivalent to the mathematical function provided the code would need to be:
import math
#assuming x equals 2
x = 2
function1 = round(10 * math.log(x,10) + 5)
function2 = round(10 * math.log(x,10)) + 5)
function3 = 10 * round(math.log(x,10)) + 5)
function4 = 10*math.log(x,10)+5
print(function1)
print(function2)
print(function3)
print(function4)
Now, assuming x = 2, the calculations for the mathematical equation is 8.01029995664
Looking at the printed output from the above code:
8
8
5
8.010299956639813
It clearly shows that functions 1,2 and 4 are roughly mathematically equivalent with function 3 being incorrect. This is because the round function uses Half and Above rule to round up. Math.log(2,10) results in 0.3, so when the round function happens it drops to zero.
As for the equivalence of int() and round() the link referenced by IMCoins is pretty good. The summation is that int() removes decimal values from a number and the round uses the half and above rule so it will act like the int() for anything less than x.5.
As for the speed question, if accuracy is non-negotiable it would be best to round upon completion of the answer due to the same reasons as why function 3 was wrong above. If you're fairly certain you can round safely at a step, then I agree with the answer above to use CProfile and find the bottlenecks
Hope this helps.
I have no clue, but let's see :)
import time
import math
n = 1000000
x = 5
def timeit(f):
t_0 = time.perf_counter()
for _ in range(n):
f()
t_1 = time.perf_counter()
print((t_1 - t_0)/ n)
def fun1():
round(10 * math.log(x) + 5)
def fun2():
round(10 * math.log(x)) + 5
def fun3():
10 * round(math.log(x)) + 5
[timeit(_) for _ in [fun1, fun2, fun3]]
On my computer the last one is slightly faster than the others.

Python 3, context based division

I'm trying to find out if numbers divide cleanly by seeing if they divide into a float or an int, for example:
10/2 = 5
10/3 = 3.333
The problem is, as I understand it, you can either use / and get ONLY float results or use // and get ONLY int results. I'm trying to figure out a way to see if some number n is prime.
The idea I had was to see if all numbers between 1 and n-1 divide into floats, as that would mean none of them divide cleanly.
This is an exercise gauging my ability for an introductory course, I realize there may be some library I can import but I'm supposed to solve this problem using methods that are at my level and importing libraries isn't.
So I was wondering if theres a way to use a divison which will return the true type of the answer, if such a question even makes sense.
To see if a number "divides cleanly", you want to use the %1 operator:
10 % 3 # 1
11 % 3 # 2
12 % 3 # 0
Clearly if a divides b "cleanly", then the result is of b % a is 0.
1Modulus operator

adjusting floats to maintain high precision

I am writing some Python code that requires a very high degree of precision. I started to use Numpy float64, but that didn't work as required, and I then started using the "Decimal" module, which then worked fine.
I would ideally prefer, however, to use floats rather than use the decimal module - and I recall someone once telling me that it's possible manipulate floats in some way so that the level of precision can be achieved (by multiplying or something?).
Is this true or am I misremembering? Sorry if this is a little vague.
Thank you!
It depends on the kind of number you have. For example if you are adding values in the interval [1...2) you might be better of using offsettet values:
>>> a = 1.0000000000000000001
>>> a
1.0
>>> a+a
1.0
>>> a = 0.0000000000000000001
>>> a
1e-19
For simpler storage you can write them as tuple (n, f) with n being a natural number (int) and f the fraction in the interval [0...1).
Computation with such kind of values is tricky however.
>>> (1+1, a+a)
(2, 2e-19)
If in doubt stick with Decimal or use bigfloat as suggested by BenDundee.
Another useful package is mpmath:
import mpmath as mp
p.dps = 64 #64 decimal places
msqrt(3)/2
mpf('0.8660254037844386467637231707529361834714026269051903140279034897246')
p.dps = 30 #30 decimal places
mpf('0.866025403784438646763723170752918')

Floating point arithmetics: Possible unsafe reliance on specific comparison?

The following python code calculates the number of iterations to do stuff based on some variables.
# a - b - c is always a multiple of d.
i = (a - b - c) / d
while i:
# do stuff
i -= 1
The variables will all be of the same type, that is only ints or floats or whatever. My concern is whether it will work correctly if the values are floats. I know enough to always consider the pitfalls of relying on exact float values. But I can't tell if the above is dangerous or not. I can use i = int(round((a - b - c) / d)), but I am curious as to understand floats better.
It all comes down to the following: a - b - c is an exact multiple of d. So I am relying on (a-b-c)/d to become a value i that I can subtract 1 from and get the expected number of iterations in the while loop, with the implied assumption that i == 0 becomes true. That is, can calculated multiples like this be decremented by 1 to reach exactly 0?
I would like to not only know if it is unsafe, but more importantly, what do I need to understand about floating point to resolve a question like this? If someone knows decisively whether this is safe or not, would it be possible to explain how so?
You can use the decimal module to get an idea of what "hides" between a floating point number such as 0.3:
>>> from decimal import Decimal
>>> Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')
Note that Python 2.7 changed how floating point numbers are written (how repr(f) works) so that it now shows the shortest string that will give the same floating point number if you do float(s). This means that repr(0.3) == '0.3' in Python 2.7, but repr(0.3) == '0.29999999999999999' in earlier versions. I'm mentioning this since it can confuse things further when you really want to see what's behind the numbers.
Using the decimal module, we can see the error in a computation with floats:
>>> (Decimal(2.0) - Decimal(1.1)) / Decimal(0.3) - Decimal(3)
Decimal('-1.85037170771E-16')
Here we might expect (2.0 - 1.1) / 0.3 == 3.0, but there is a small non-zero difference. However, if you do the computation with normal floating point numbers, then you do get zero:
>>> (2 - 1.1) / 0.3 - 3
0.0
>>> bool((2 - 1.1) / 0.3 - 3)
False
The result is rounded somewhere along the way since 1.85e-16 is non-zero:
>>> bool(-1.85037170771E-16)
True
I'm unsure exactly where this rounding takes place.
As for the loop termination in general, then there's one clue I can offer: for floats less than 253, IEEE 754 can represent all integers:
>>> 2.0**53
9007199254740992.0
>>> 2.0**53 + 1
9007199254740992.0
>>> 2.0**53 + 2
9007199254740994.0
The space between representable numbers is 2 from 253 to 254, as shown above. But if your i is an integer less than 253, then i - 1 will also be a representable integer and you will eventually hit 0.0, which is considered false in Python.
I will give you a language-agnostic answer (I don't really know Python).
There are multiple potential problems in your code. Firstly, this:
(a - b - c)
If a is (for example) 109, and b and c are both 1, then the answer will be 109, not 109-2 (I'm assuming single-precision float here).
Then there's this:
i = (a - b - c) / d
If numerator and denominator are numbers that can't be exactly represented in floating-point (e.g. 0.3 and 0.1), then the result might not be an exact integer (it might be 3.0000001 instead of 3). Therefore, your loop will never terminate.
Then there's this:
i -= 1
Similarly to above, if i is currently 109, then the result of this operation will still be 109, so your loop will never terminate.
Therefore, you should strongly consider performing all the calculations in integer arithmetic.
You're right that there could be a non-convergence on zero (at least for more iterations than you intend). Why not have your test be: while i >= 1. In that case, as with integers, if your i value dips below 1, the loop will end.

Categories

Resources