Best way to detect floating round off error in python - python

So I have a list of floating numbers, some of them have round off errors and appears in the form 0.3599999. It is trivial to detect by convert it to string and see if there is a bunch of 999 following. I wonder how a python hacker will do for this or if there is a mathematical way to do this.
Thanks

Consider using Python's decimal module
>>> from decimal import Decimal
>>> Decimal(0.35)
Decimal('0.34999999999999997779553950749686919152736663818359375')

Also have a look at Numpy's assert_approx_equal() function:
>>> np.testing.assert_approx_equal(0.12345677777777e-20, 0.1234567e-20)
>>> np.testing.assert_approx_equal(0.12345670e-20, 0.12345671e-20,
significant=8)
>>> np.testing.assert_approx_equal(0.12345670e-20, 0.12345672e-20,
significant=8)
...
<type 'exceptions.AssertionError'>:
Items are not equal to 8 significant digits:
ACTUAL: 1.234567e-021
DESIRED: 1.2345672000000001e-021

Related

Dynamic decimal point Python float

I'm looking for a way to neatly show rounded floats of varying decimal lengh.
Example of what I'm looking for:
In: 0.0000000071234%
Out: 0.0000000071%
In: 0.00061231999999%
Out: 0.0061%
In: 0.149999999%
Out: 0.15%
One way to do it would be:
def dynamic_round(num):
zeros = 2
original = num
while num< 0.1:
num*= 10
zeros += 1
return round(original, zeros)
I'm sure however there is a much cleaner way to do the same thing.
Here's a way to do it without a loop:
a = 0.003123
log10 = -int(math.log10(a))
res = round(a, log10+2)
==> 0.0031
This post answers your question with a similar logic
How can I format a decimal to always show 2 decimal places?
but just to clarify
One way would be to use round() function also mentioned in the documentation
built-in functions: round()
>>> round(number[,digits])
here digit refers to the precision after decimal point and is optional as well.
Alternatively, you can also use new format specifications
>>> from math import pi # pi ~ 3.141592653589793
>>> '{0:.2f}'.format(pi)
'3.14'
here the number next to f tells the precision and f refers to float.
Another way to go here is to import numpy
>>>import numpy
>>>a=0.0000327123
>>>res=-int(numpy.log10(a))
>>>round(a,res+2)
>>>0.000033
numpy.log() also, takes an array as an argument, so if you have multiple values you can iterate through the array.

How to get the correct decimal result

I'm trying to write a program to search for duplicate representations of integers in fractional number bases. Consequently, I have to do things like this:
1.1**7
which equals 1.9487171. However, python automatically represents that result as a float, whereas the given value is exact. This is what I need, which is not the same as rounding a float. I also must allow the program to specify how many decimal places there are. I've tried using the decimal module but can't quite get it to work. What would be the best way to do this?
decimal.Decimal arguments should be strings. If you use a float, it carries along it's imprecision:
>>> decimal.Decimal('1.1')**7
Decimal('1.9487171')
>>>
VS
>>> decimal.Decimal(1.1)**7
Decimal('1.948717100000001101423574568')
>>>
The decimal module will give you exact results:
>>> Decimal('1.1') ** 7
Decimal('1.9487171')
For non-decimal bases, the fractions module will do the exact arithmetic. The only issue though is that the output is in fractional form rather than indicating the decimal notation (likely with repeating, non-terminating sequences) that you seem to be looking for:
>>> Fraction(3, 7) ** 5
Fraction(243, 16807)
>>> Context(prec=200).divide(243, 16807)
Decimal('0.014458261438686261676682334741476765633367049443684179211043017790206461593383709168798714821205450110073183792467424287499256262271672517403462842863092758969477003629440114238115071101326828107336229')
fractional number bases
Sounds like fractions, no?
>>> import fractions
>>> fractions.Fraction(11, 10) ** 7
Fraction(19487171, 10000000)
>>> fractions.Fraction(13, 11) ** 7
Fraction(62748517, 19487171)
Have you tried checking for equality to within a tolerance? E.g.
def approx(left, right, tolerance=1**10-6):
if left - right < tolerance:
return True
else:
return False

Finding the last digit of decimal number

We all know that if we want to find the last number of 1182973981273983 which is 3 we simply do this:
>>> print(1182973981273983 % 10)
3
But if I want to get the last number of 2387123.23 I was thinking of doing this:
>>> 2387123.23 % 10 ** (-1 * 2)
0.009999999931681564
But it doesn't work. What is the mathematical way of getting the last number a decimal number.
p.s. String solutions are invalid. We are programmers we need to know how math works.
As people have already pointed out in the comments, this is not possible for floating point numbers; the concept of 'last decimal' simply doesn't apply. See links in comments for more details.
On the other hand, this would work if you were using fixed point arithmetic (i.e. the Decimal type). Then a solution might look like this:
>>> import decimal
>>> d = decimal.Decimal('3.14')
>>> d.as_tuple().digits[-1]
4

converting numbers to metric unit in python

when doing this in python 100*0.000001 I got 9.999999999999999e-05
What I need to do to get 1e-05?
floating point numbers are not exact. You could represent it as 1e-4 when printing, or use Decimal to get an exact value. e.g.
>>> print '{:4.0e}'.format(100*0.000001)
1e-04
or
>>> Decimal(100)*Decimal('0.000001')
Decimal('0.000100')
Don't do the multiplication:
>>> 100e-7
1e-05
Realize though that 0.1 is an infinitely repeating number in binary and you will discover approximations other artifacts before too long:
>>> 100e-7*.1
1.0000000000000002e-06
Then just deal with the issue in formating the output:
>>> '{:e}'.format(100*0.000001)
'1.000000e-04'
>>> '{:e}'.format(100*0.0000001)
'1.000000e-05'
>>> '{:e}'.format(100*0.00000001)
'1.000000e-06'

how to change 39.54484700000000 to 39.54 and using python [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
python limiting floats to two decimal points
i want to set 39.54484700000000 to 39.54 using python ,
how to get it ,
thanks
If you want to change the actual value, use round as Eli suggested. However for many values and certain versions of Python this will not result be represented as the string "39.54". If you want to just round it to produce a string to display to the user, you can do
>>> print "%.2f" % (39.54484700000000)
39.54
or in newer versions of Python
>>> print("{:.2f}".format(39.54484700000000))
39.54
or with the fstrings
>>> print(f'{39.54484700000000:.2f}')
39.54
Relevant Documentation: String Formatting Operations, Built-in Functions: round
How about round
>>> import decimal
>>> d=decimal.Decimal("39.54484700000000")
>>> round(d,2)
39.54
You can use the quantize method if you're using a Decimal:
In [24]: q = Decimal('0.00')
In [25]: d = Decimal("115.79341800000000")
In [26]: d.quantize(q)
Out[26]: Decimal("115.79")
>>> round(39.54484700000000, 2)
39.54
Note, however, that the result isn't actually 39.54, but 39.53999999999999914734871708787977695465087890625.
Use round:
Return the floating point value x
rounded to n digits after the decimal
point. If n is omitted, it defaults to
zero. The result is a floating point
number.
Values are rounded to the closest
multiple of 10 to the power minus n;
if two multiples are equally close,
rounding is done away from 0
>>> round(39.544847, 2)
39.539999999999999
>>>
Note that since 39.54 isn't exactly represantable with floating points on my PC (x86), the result is an epsilon off. But that makes no difference (and is a whole different issue with many SO questions and answers on it). If you convert it to a string properly, you'll see what you expect:
>>> "%.2f" % round(39.544847, 2)
'39.54'
Eli mentions using the round function -- depending on your requirements, you may want to return a Decimal object instead.
>>> from decimal import Decimal
>>> float_val = 39.54484700000000
>>> decimal_val = Decimal("%.2f" % float_val)
>>> print decimal_val
39.54
Using Decimal objects lets you specify the exact number of decimal places that you want to keep track of, so you avoid ending up with a floating point number that is represented as 39.539999999999999. Specifically, if you are doing financial calculations, you will almost always be advised to stay away from floating-point numbers.
You can't cast floats directly into Decimals, however (the floats are imprecise, and Python can't guess how you want them rounded,) so I will almost always convert them to a rounded string representation first (that's the "%.2f" % float_val -- %.2f means to display only two decimals, and then create a Decimal out of that.

Categories