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
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 1 year ago.
a = 1000000000
b = 1000000
max_ = int((a - b + 1) * (a - b) / 2)
I have this line in my code and when "a" equals a billion (1000000000) and "b" equals a million (1000000), the result came up with the answer "499000500499500032". The correct result of this arithmetical calculation is "499000500499500000".
I searched for why it does so but couldn't find anything. I am using Python 3.9.5 if it matters in this case
.
Python uses the CPU's native float which is a binary estimate of the true floating point number. Its not a problem with python per se, its the inherent imprecision in fixed length binary floats. Simply writing your wanted value as a float demonstrates the problem:
>>> f"{499000500499500000.:f}"
'499000500499500032.000000
If you need more precision than float offers, the decimal module may work for you.
>>> from decimal import Decimal
>>> a = Decimal(1000000000)
>>> b = Decimal(1000000)
>>> max_d = (a - b + 1) * (a - b) / 2
>>> max_d
Decimal('499000500499500000')
>>> max_ = int(max_d)
>>> max_
499000500499500000
float exists, even though it is an estimate of a true real number, because this lack of precision can usually be factored into the algorithm. When this error is too much, or when you are doing something like accounting where the error is significant, there is the alternative decimal.
See Floating Point Arithmetic: Issues and Limitations
Another option is to use floor division which doesn't go through float.
>>> a = 1000000000
>>> b = 1000000
>>> (a - b + 1) * (a - b) // 2
499000500499500000
That looks better! But, there is still a lack of precision depending on what you are dividing.
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".
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
I have float 32 numbers (let's say positive numbers) in numpy format. I want to convert them to fixed point numbers with predefined number of bits to reduce precision.
For example, number 3.1415926 becomes 3.25 in matlab by using function num2fixpt.
The command is num2fixpt(3.1415926,sfix(5),2^(1 + 2-5), 'Nearest','on') which says 3 bits for integer part, 2 bits for fractional part.
Can I do the same thing using Python
You can do it if you understand how IEEE floating point notation works. Basically you'll need to convert to a python LONG, do bitwise operators, then covert back. For example:
import time,struct,math
long2bits = lambda L: ("".join([str(int(1 << i & L > 0)) for i in range(64)]))[::-1]
double2long = lambda d: struct.unpack("Q",struct.pack("d",d))[0]
double2bits = lambda d: long2bits(double2long(d))
long2double = lambda L: struct.unpack('d',struct.pack('Q',L))[0]
bits2double = lambda b: long2double(bits2long(b))
bits2long=lambda z:sum([bool(z[i] == '1')*2**(len(z)-i-1) for i in range(len(z))[::-1]])
>>> pi = 3.1415926
>>> double2bits(pi)
'0100000000001001001000011111101101001101000100101101100001001010'
>>> bits2long('1111111111111111000000000000000000000000000000000000000000000000')
18446462598732840960L
>>> double2long(pi)
4614256656431372362
>>> long2double(double2long(pi) & 18446462598732840960L)
3.125
>>>
def rshift(x,n=1):
while n > 0:
x = 9223372036854775808L | (x >> 1)
n -= 1
return x
>>> L = bits2long('1'*12 + '0'*52)
>>> L
18442240474082181120L
>>> long2double(rshift(L,0) & double2long(pi))
2.0
>>> long2double(rshift(L,1) & double2long(pi))
3.0
>>> long2double(rshift(L,4) & double2long(pi))
3.125
>>> long2double(rshift(L,7) & double2long(pi))
3.140625
This will only truncate the number of bits though, not round them. The rshift function is necessary because python's right-shift operator fills the empty leftmost bit with a zero. See a discription of IEEE floating point here.
You can use fxpmath module to work with fractional fixed-point in python.
Module repository: https://github.com/francof2a/fxpmath
from fxpmath import Fxp
pi_fxp = Fxp(None, signed=False, n_word=5, n_frac=2) # create fixed-point object (3 bit for intefer, 2 for fractional)
pi_fxp.rounding = 'around' # define rounding method, default is `trunc`.
pi_fxp(3.1415926) # set value
print(pi_fxp) # printed value = 3.25
You can round to binary fixed precision without explicit type conversions that tend to generate a lot of interpreter overhead:
import numpy as np
n_bits = 2
f = (1 << n_bits)
a = np.linspace(1, 2, 11)
a_fix = np.round(a*f)*(1.0/f)
print a
print a_fix
Results in
[ 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2. ]
[ 1. 1. 1.25 1.25 1.5 1.5 1.5 1.75 1.75 2. 2. ]
The example uses numpy, but that's just for the convenience of generating a list of example values. Python's built-in round will work just as well for single values:
x=3.1415926
x_fix = round(x*f)/float(f)
print x_fix
Note that both f and 1.0/f have an exact floating-point representation; therefore, the multiplication and division are exact, without rounding errors. Also note that multiplying by 1.0/f is about 3x faster than dividing directly in the case of large arrays.
This approach doesn't control the number of bits for the integer part, so if you want the numbers to be capped or wrap around if they are too big, you'd have to do a bit more bit-shifting.
numfi is a python library that mimic matlab's fi fixed point object, it's more like fixdt in simulink, but you can change num2fixpt to numfi by define word/fraction length instead of scaling
>>> from numfi import numfi
>>> x = numfi(3.1415926,1,5,2) # 5 word length = 2 fraction + 2 integer + 1 signed
>>> x
numfi([3.25]) s5/2-r/s
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