Rounding in Python with decimal [duplicate] - python

This question already has answers here:
Rounding error in Python with non-odd number? [duplicate]
(1 answer)
Python 3.x rounding behavior
(13 answers)
Closed 1 year ago.
We all know the rounding issues in Python -- that it's based on float point arithmetic, which is convenient for computers but does not always match practical, human understanding. There's plenty of questions on this on StackOverflow, though most revolve around preserving tiny decimal places, which is different than what I need below.
The solution to these rounding issues is to use the decimal module. Yet, I must be doing something very wrong. Please, consider this, in Octave/Matlab:
>> round(2.5)
ans = 3
>> round(3.5)
ans = 4
The above are the correct results (valid in finance, applied physics, medicine, etc). We know that the same will fail in Python:
>>> round(2.5)
2
>>> round(3.5)
4
No suprise here. But when I use decimal, I still don't receive the correct answer, and here I must be doing something wrong. Starting from the example in https://docs.python.org/3/library/decimal.html:
>>> from decimal import *
>>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
Straightforward, right? But then:
>>> Decimal('3.225').quantize(TWOPLACES)
Decimal('3.22') # Wrong result. Correct would be 3.23
>>> Decimal('3.235').quantize(TWOPLACES)
Decimal('3.24') # Correct result.
So, what can I do to have the correct (as in "real world", "human-based") answer, in a fast, efficient, pythonic manner, and use the result in further computations?
EDIT: I'm using Python 3.7.3.

This happens by design and is not an error.
See answers to this question as to why this happens: Python 3.x rounding behavior
You can set the desired rounding method as a parameter of quantize:
Decimal('3.235').quantize(TWOPLACES, rounding=ROUND_HALF_UP)

Related

math.pi doesn't give me the good value [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 1 year ago.
I use math.pi with python:
import Decimal as dc
dc.getcontext().prec=100
pi = dc.Decimal(math.pi)
and I get:
3.141592653589793115997963468544185161590576171875
and on Internet, I get:
3,141592653589793238462643383279502884197169399375
Why doesn't python give a good value? How to improve the situation?
I tried with and without Decimal.
As indicated in the comments and in the documentation of Python math module, math.pi holds a floating-point value. Floating-point is inaccurate by design, because there is a finite number of bits dedicated to keeping the precision. You can read https://docs.python.org/3/tutorial/floatingpoint.html to understand how float is represented, and how this will impact you during programming (in all languages, not only Python).
How to get your accurate value of pi? As mentioned by Tom Karzes, you can use Decimal module and feed it with as many digits as you want. Let's take the first 30 digits of pi from https://www.angio.net/pi/digits/pi1000000.txt, and your code would look like this:
pi_30_decimal_places = Decimal("3.141592653589793238462643383279")

Getting inaccurate answers when doing math with large numbers in python [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 1 year ago.
I am writing python code that involves a series of math calculations. One such is the following operation:
result1 = float1 % float2 //modulo operation to find the remainder
where float1 = 6816605016955680000000 and float2 = 1577917828000
The result I get is 1573597498272 (reverse math shows that this is not accurate). I get the same result on Excel or Numbers as well.
However, when I try this on a quad-core system, Excel and Numbers give a very different result which is 1573597828000 (reverse math shows this is accurate). The python program continues to give the same old result even on the quad-core system.
(Python version is 3.7.2 on my system and 3.9 on quad-core system).
What can I do to ensure python gives me the accurate result? Any guidance would be super valuable. Thanks in advance.
Python numbers are not accurate for large numbers, if you want more accurate precision, use the Decimal class:
from decimal import Decimal
Decimal(6816605016955680000000) % Decimal(1577917828000)
Output:
Decimal('1573597828000')
This should give you consistent results across different systems.

Using int(.) to get rid of decimals [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
I came across the following strange result in Python (I use Spyder environment). Any idea what is going on? And how can I fix this? I truly don't want to put 20 zeros in front of my variable nor using numpy for such a simple work makes sense!
int(121212000000000000000000000000000000000000000000000000)
Out[27]: 121212000000000000000000000000000000000000000000000000
int(121212*1e20)
Out[28]: 12121199999999999802867712
int(121212*10e20)
Out[29]: 121211999999999993733709824
It has to do with floating point precision.
You can use the decimal module like so:
>>> from decimal import Decimal
>>> Decimal(121212) * Decimal('10e20')
Decimal('121212000000000000000000000')
For more info, see the following Python tutorial.

Mathematics and behavior with floats vs ints [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Why does Python return 0 for simple division calculation?
(6 answers)
Closed 5 years ago.
This is driving me mad... Of all the years I've been using python, this is just now starting to present itself. How I managed to dodge it up until now is beyond me.
If you open a python idle and try this equation...
4/32*100
You'll get '0' as an answer. Now try the same equation using floats....
4.0/32.0*100.0 (or just the first number 4.0/32*100)
You now get an actual percentage.
WTF!?
Is this some kind of python error!? Even a calculation can do the equation and spit out a percentage.
So why can't python see a 4 as 4.0. Better question... What is the interpreter actually seeing if it's not seeing a 4(4.0)?
Someone please clear this up so I can feel professional with python again (lol).
In Python 2, int type division ignores the decimal values of the division.
For example, 1/2 = 0.5, but in int type division, 1/2 will evaluate to 0 because it ignores the decimal values.
Thus, in your case with 4/32*100, 4/32will first evaluate to 0 and then 0*100 will finally equal 0.
On the other hand, in float type division, it will evaluate answers as we would expect (not in a strictly precise definition though, look here for further information).
For Python 2.x, dividing two integers or longs uses integer division, also known as "floor division"(applying the floor function after division)
For Python 3.x, "/" does "true division" for all types.
To make python perform true division, cast any of the denominator for numerator to become float.
float(4)/32*100
or
4/float(32)*100
or doing below to make python 2 division behave like python 3 division
from __future__ import division
4/32*100

Rounding very large numbers in Python (left of the decimal) [duplicate]

This question already has answers here:
round() doesn't seem to be rounding properly
(20 answers)
Closed 6 years ago.
The community reviewed whether to reopen this question 5 months ago and left it closed:
Original close reason(s) were not resolved
The Python round() function will theoretically take negative numbers to round to places left of the decimal. [ I.e. round(150, -2) => 200]
However, it seems to be very susceptible to floating point error.
For example, given a large number say 2e25, it gives weird results.
2e25 === 20000000000000000000000000
But, round(2e25, -23) gives a value like
20000000000000000273942742
When it should just be getting 20000000000000000000000000
I know there's a formatting function, a la this thread:
round() in Python doesn't seem to be rounding properly
However, that only seems to work for rounding to the right of the decimal. Am I wrong? Is there another way to do this? Very frustrating trying to get the math right.
Thanks!
The problem is that 2e25 doesn't actually equal 20000000000000000000000000.
>>> 2e25 == 20000000000000000000000000
False
>>> 2e25 == 20000000000000001811939328
True
The float type doesn't have enough precision to represent such a large integer exactly. Unless you have a good reason for using floating-point values, use integers instead.

Categories

Resources