Summation of large numbers in python yields the maximal parameter - python

In my program I use numpy to get number's exponents, then I use the sum function to summarize them.
I've noticed that summarizing those large numbers, with or without numpy, results in the largest parameter being returned, unchanged.
exp_joint_probabilities=[ 1.57171938e+81, 1.60451506e+56, 1.00000000e+00]
exp_joint_probabilities.sum()
=> 1.571719381352921e+81
The same with just python:
(1.57171938e+81+1.60451506e+56+1.00000000e+00)==1.57171938e+81
=>True
Is this a problem with approximation? Should I use a larger datatype to represent the numbers?
How can I get a more accurate result for these kind of calculations?

You could use the decimal standard library:
from decimal import Decimal
a = Decimal(1.57171938e+81)
b = Decimal(1.60451506e+56)
d = a + b
print(d)
print(d > a and d > b)
Output:
1.571719379999999945626903708E+81
True
You could convert it back to a float afterwards, but this will cause the same problem as before.
f = float(d)
print(f)
print(f > a and f > b)
Output:
1.57171938e+81
False
Note that if you store Decimals in your numpy arrays, you will lose fast vectorized operations, as numpy does not recognize Decimal objects. Though it does work:
import numpy as np
a = np.array([1.57171938e+81, 1.60451506e+56, 1.00000000e+00])
d = np.vectorize(Decimal)(a) # convert values to Decimal
print(d.sum())
print(d.sum() > d[0]
Output:
1.571719379999999945626903708E+81
True

1.57171938e+81 is a number with 81 digits, of which you only enter the first 9. 1.60451506e+56 is a much much much smaller number, with only 56 digits.
What kind of answer are you expecting? The first utterly dwarfs the second. If you want something of a similar precision to your original numbers (and that's what you get using floats), then the answer is simply correct.
You could use ints:
>>> a = int(1.57171938e+81)
>>> b = int(1.60451506e+56)
>>> a
571719379999999945626903548020224083024251666384876684446269499489505292916359168L
>>> b
160451506000000001855754747064077065047170486040598151168L
>>> a+b
1571719379999999945626903708471730083024253522139623748523334546659991333514510336L
But how useful that is is up to you.

It does seem to be a problem with approximation:
>>> 1.57171938e+81 + 1.60451506e+65 > 1.57171938e+81
<<< True
>>> 1.57171938e+81 + 1.60451506e+64 > 1.57171938e+81
<<< False
You can get arount this by casting to int:
>>> int(1.57171938e+81) + int(1.60451506e+64) > int(1.57171938e+81)
<<< True

Related

Take number after floating point

I have this value :
a = 1.01010101
And i need to take all the numbers after the point,
convert them into an int.
Create a new variable and put this int in an new variable.
So i need an output like this
b = 01010101
I can't make this:
a -= 1
b = a*(10**8)
because I don't know the number before the point.
Is it also possible to do it without writing a new function?
Sorry for my english.
Have a good day
The math.trunc() function will give you the integer part:
>>> import math
>>> math.trunc(1.01010101)
1
you can then subtract, however you'll likely run into ieee floating point issues that may be surprising:
>>> a = 1.01010101
>>> a -= math.trunc(a)
>>> a
0.010101010000000077
>>> b = a * 10**8
>>> b
1010101.0000000077
in many cases you can just truncate the last number to get the expected integer, but I'd suggest reading https://docs.python.org/2/tutorial/floatingpoint.html to get a deeper understanding.
Python has a decimal module that handles base-10 arithmetic more faithfully:
import decimal.Decimal as D
>>> a = D('1.01010101')
>>> a
Decimal('1.01010101')
>>> math.trunc(a)
1
>>> a -= math.trunc(a)
>>> a
Decimal('0.01010101')
>>> a * 10**8
Decimal('1010101.00000000')
>>> b = int(a * 10**8)
>>> b
1010101
in this version there will be no floating point artifacts in the b = ... line.
You can do this:
a = 1.01010101
b = str(a).split('.')[1]
This should give you "01010101".

How to sum very large numbers to 1 in python

So imagine I have
>>> a = 725692137865927813642341235.00
If I do
>>> sum = a + 1
and afterwards
>>> sum == a
True
This is because a is bigger than a certain threshold.
Is there any trick like the logsumexp to perform this?
PS: a is an np.float64.
If a has to be specifically of type float, no, then that's not possible. In fact, the imprecision is much greater:
>>> a = 725692137865927813642341235.00
>>> a + 10000 == a
True
However, there are other data types that can be used to represent (almost) arbitrary precision decimal values or fractions.
>>> d = decimal.Decimal(a)
>>> d + 1 == d
False
>>> f = fractions.Fraction(a)
>>> f + 1 == f
False
(Note: of course, doing Decimal(a) or Fraction(a) does not magically restore the already lost precision of a; if you want to preserve that, you should pass the full value as a string.)
0) import decimal
1) setup appropriate precision of the decimal.getcontext() ( .prec attribute )
2) declare as decimal.Decimal() instance
>>> import decimal
>>> decimal.getcontext().prec
28
>>> decimal.getcontext().prec = 300
>>> dec_a = decimal.Decimal( '725692137865927813642341235.0' )
It is a pleasure to use decimal module for extremely extended numerical precision solvers.
BONUS:
Decimal module has very powerful context-methods, that preserve the decimal-module's strengths .add(), .subtract(), .multiply(), .fma(), .power() so as to indeed build an almost-infinite precision solver methods ...
Definitely worth mastering these decimal.getcontext() methods - your solvers spring into another league in precision and un-degraded convergence levels.
Will dividing a by 100,000 then adding 1 then times it back up again?
Eg.
a=725692137865927813642341235.00
a /= 100000
a += 0.00001
a *= 100000

How to deal with exponent overflow of 64float precision in python?

I am a newbie in python sorry for the simple question.
In the following code, I want to calculate the exponent and then take the log.
Y=numpy.log(1+numpy.exp(1000))
The problem is that when I take the exponent of 710 or larger numbers the numpy.exp() function returns 'inf' even if I print it with 64float it prints 'inf'.
any help regarding the problem will be appreciated.
You can use the function np.logaddexp() to do such operations. It computes logaddexp(x1, x2) == log(exp(x1) + exp(x2)) without explicitly computing the intermediate exp() values. This avoids the overflow. Since exp(0.0) == 1, you would compute np.logaddexp(0.0, 1000.0) and get the result of 1000.0, as expected.
Check this out:
>>> x = numpy.exp(100)
>>> y = x+1
>>> y==x
True
so even with 100 (which computes all right), adding 1 (or even a very big number), the lowest value is absorbed and has absolutely no effect in the addition. Both values are strictly equal.
Playing with sys.float_info.epsilon I tested that:
>>> numpy.log(1e20+numpy.exp(100))==numpy.log(numpy.exp(100))
True
>>> numpy.log(1e30+numpy.exp(100))==numpy.log(numpy.exp(100))
False
so even a value like 1e20 is absorbed by exp(100) ...
So you would get exactly 1000.0 as your result even if it worked.
Use the decimal library:
>>> import numpy as np
>>> np.exp(1000)
inf
>>> from decimal import Decimal
>>> x = Decimal(1000)
>>> np.exp(x)
Decimal('1.970071114017046993888879352E+434')

Python3.3 rounding up

In Python I would like to divide two numbers and if the answer is not an integer I want the number to be rounded up to the number above.
For example 100/30 not to give 33.3 but to give 4.
Can anyone suggest how to do this? Thanks.
You can use the math.ceil() function:
>>> import math
>>> math.ceil(100/33)
4
you can use the ceil function in math library that python has, but also you can take a look why in a logical sense
a = int(100/3) # this will round down to 3
b = 100/3 # b = 33.333333333333336, a and b are not equal
so we can generalize into the following
def ceil(a, b):
if (b == 0):
raise Exception("Division By Zero Error!!") # throw an division by zero error
if int(a/b) != a/b:
return int(a/b) + 1
return int(a/b)

Compare decimals in python

I want to be able to compare Decimals in Python. For the sake of making calculations with money, clever people told me to use Decimals instead of floats, so I did. However, if I want to verify that a calculation produces the expected result, how would I go about it?
>>> a = Decimal(1./3.)
>>> a
Decimal('0.333333333333333314829616256247390992939472198486328125')
>>> b = Decimal(2./3.)
>>> b
Decimal('0.66666666666666662965923251249478198587894439697265625')
>>> a == b
False
>>> a == b - a
False
>>> a == b - Decimal(1./3.)
False
so in this example a = 1/3 and b = 2/3, so obviously b-a = 1/3 = a, however, that cannot be done with Decimals.
I guess a way to do it is to say that I expect the result to be 1/3, and in python i write this as
Decimal(1./3.).quantize(...)
and then I can compare it like this:
(b-a).quantize(...) == Decimal(1./3.).quantize(...)
So, my question is: Is there a cleaner way of doing this? How would you write tests for Decimals?
You are not using Decimal the right way.
>>> from decimal import *
>>> Decimal(1./3.) # Your code
Decimal('0.333333333333333314829616256247390992939472198486328125')
>>> Decimal("1")/Decimal("3") # My code
Decimal('0.3333333333333333333333333333')
In "your code", you actually perform "classic" floating point division -- then convert the result to a decimal. The error introduced by floats is propagated to your Decimal.
In "my code", I do the Decimal division. Producing a correct (but truncated) result up to the last digit.
Concerning the rounding. If you work with monetary data, you must know the rules to be used for rounding in your business. If not so, using Decimal will not automagically solve all your problems. Here is an example: $100 to be share between 3 shareholders.
>>> TWOPLACES = Decimal(10) ** -2
>>> dividende = Decimal("100.00")
>>> john = (dividende / Decimal("3")).quantize(TWOPLACES)
>>> john
Decimal('33.33')
>>> paul = (dividende / Decimal("3")).quantize(TWOPLACES)
>>> georges = (dividende / Decimal("3")).quantize(TWOPLACES)
>>> john+paul+georges
Decimal('99.99')
Oups: missing $.01 (free gift for the bank ?)
Your verbiage states you want to to monetary calculations, minding your round off error. Decimals are a good choice, as they yield EXACT results under addition, subtraction, and multiplication with other Decimals.
Oddly, your example shows working with the fraction "1/3". I've never deposited exactly "one-third of a dollar" in my bank... it isn't possible, as there is no such monetary unit!
My point is if you are doing any DIVISION, then you need to understand what you are TRYING to do, what the organization's policies are on this sort of thing... in which case it should be possible to implement what you want with Decimal quantizing.
Now -- if you DO really want to do division of Decimals, and you want to carry arbitrary "exactness" around, you really don't want to use the Decimal object... You want to use the Fraction object.
With that, your example would work like this:
>>> from fractions import Fraction
>>> a = Fraction(1,3)
>>> a
Fraction(1, 3)
>>> b = Fraction(2,3)
>>> b
Fraction(2, 3)
>>> a == b
False
>>> a == b - a
True
>>> a + b == Fraction(1, 1)
True
>>> 2 * a == b
True
OK, well, even a caveat there: Fraction objects are the ratio of two integers, so you'd need to multiply by the right power of 10 and carry that around ad-hoc.
Sound like too much work? Yes... it probably is!
So, head back to the Decimal object; implement quantization/rounding upon Decimal division and Decimal multiplication.
Floating-point arithmetics is not accurate :
Decimal numbers can be represented exactly. In contrast, numbers like
1.1 and 2.2 do not have exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as
3.3000000000000003 as it does with binary floating point
You have to choose a resolution and truncate everything past it :
>>> from decimal import *
>>> getcontext().prec = 6
>>> Decimal(1) / Decimal(7)
Decimal('0.142857')
>>> getcontext().prec = 28
>>> Decimal(1) / Decimal(7)
Decimal('0.1428571428571428571428571429')
You will obviously get some rounding error which will grow with the number of operations so you have to choose your resolution carefully.
There is another approach that may work for you:
Continue to do all your calculations in floating point values
When you need to compare for equality, use round(val, places)
For example:
>>> a = 1./3
>>> a
0.33333333333333331
>>> b = 2./3
>>> b
0.66666666666666663
>>> b-a
0.33333333333333331
>>> round(a,2) == round(b-a, 2)
True
If you'd like, create a function equals_to_the_cent():
>>> def equals_to_the_cent(a, b):
... return round(a, 2) == round(b, 2)
...
>>> equals_to_the_cent(a, b)
False
>>> equals_to_the_cent(a, b-a)
True
>>> equals_to_the_cent(1-a, b)
True

Categories

Resources