Trying to add zeroes and a random digit in floats in Python.
I have a code that just loops through and shows the cumulative frequency at each step and the final sum should be 1 but it isn't working.
Here is the output:
0.11
0.197
0.279
0.35700000000000004
0.43000000000000005
0.502
0.569
0.6299999999999999
0.6829999999999999
0.723
0.761
0.794
0.8240000000000001
0.8520000000000001
0.8790000000000001
0.9040000000000001
0.9270000000000002
0.9470000000000002
0.9630000000000002
0.9770000000000002
0.9870000000000002
0.9961000000000002
1.0005000000000002
1.0032
1.0056
1.0077
1.0077
I think this is being caused by the long row of zeroes in some numbers like 0.35700000000000004 in the 4th one. Also, many values are changing like in the first step it should be 0.11 and not 0.197.
Example code:
for i in AlphabetWeights:
count = i+count
print(count)
This is not an arithmetic issue.. You can see that your truncation error is happening O(1e-16), as is expected. What you describe as an 'error' is on the order of 1e-3. You even see that your truncation error is cancelling out at times.. no way that your deviation of 0.0077 from the desired result 1.0 is due to floating-point arithmetic
like in the first step it should be 0.11 and not 0.197.
Check your code for bugs.. this is not floating-point arithmetic
You can use Decimal in this case. The decimal module provides support for fast correctly-rounded decimal floating-point arithmetic. Check this link: Python Decimal
Check this code:
from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7)
Decimal('0.1428571428571428571428571429')
for example:
x = 0.1
y = 0.1
z = 0.1
s = x + y + z
print(s)
the output will be :
0.30000000000000004
but
import decimal
from decimal import Decimal
x = Decimal('0.1')
y = Decimal('0.1')
z = Decimal('0.1')
s = x + y + z
print(s)
the output will be :
0.3
Related
This I imagine is extremely simple - but why in the following are the two values for y not == 0? I thought the whole point of the decimal module was to get rid of the float dust ...The following is an extremely simplified version of a mathematical routine that passes numbers around as variables.
from decimal import *
getcontext().prec = 2
q = Decimal(0.01)
x = Decimal(0.10) * Decimal(0.10)
y = Decimal(x) - Decimal(q)
print(x,y, Decimal(y))
'''
x== 0.010
y== -2.1E-19
Decimal(y) == -2.1E-19
'''
Try specifying the numbers as strings
>>> Decimal('0.10') * Decimal('0.10') - Decimal('0.0100')
>>> Decimal('0.000')
The float literal 0.10 is not precisely the mathematical number 0.10, using it to initialize Decimal doesn't avoid the float precision problem.
Instead, using strings to initialize Decimal can give you expected result:
x = Decimal('0.10') * Decimal('0.10')
y = Decimal(x) - Decimal('0.010')
This is a more detailed explanation of the point made in existing answers.
You really do need to get rid of the numeric literals such as 0.1 if you want exact decimal arithmetic. The numeric literals will typically be represented by IEEE 754 64-bit binary floating point numbers.
The closest such number to 0.1 is 0.1000000000000000055511151231257827021181583404541015625. Its square is 0.01000000000000000111022302462515657123851077828659396139564708135883709660962637144621112383902072906494140625, which is not the same as the closest to 0.01, 0.01000000000000000020816681711721685132943093776702880859375.
You can get a clearer view of what is going on by removing the prec =2 context, allowing more precise output:
from decimal import *
q = Decimal(0.01)
x = Decimal(0.10) * Decimal(0.10)
y = Decimal(x) - Decimal(q)
print(q)
print(x)
print(y)
Output:
0.01000000000000000020816681711721685132943093776702880859375
0.01000000000000000111022302463
9.020562075127831486705690622E-19
If you had used string literals, as suggested by the other responses, the conversion to Decimal would have been done directly, without going through binary floating point. Both 0.1 and 0.01 are exactly representable in Decimal, so there would be no rounding error.
# Used "==" and "is" for equality
print(48 / 10 == 48 * 0.1)
print(48 / 10 is 48 * 0.1)
print()
# Check Both Answers Individually
print(f"48 / 10 = {48 / 10}")
print(f"48 * 0.1 = {48 * 0.1}")
In the following code, I thought both expressions would equal each other, but they do not. This is what it outputs.
False
False
48 / 10 = 4.8
48 * 0.1 = 4.800000000000001
Can someone explain why there is a difference in the result, whether you are using division or multiplication?
Even though multiplying by 0.1 and dividing by 10 are mathematically equal, in a computer program they are not.
When you write 0.1 in Python, what you get is not one tenth. It's slightly more. Here's 0.1 to 40 digits of precision:
>>> "%0.40f" % 0.1
'0.1000000000000000055511151231257827021182'
The difference is due to the fact that floating point numbers use a binary representation. You cannot represent 0.1 exactly with a finite number of binary digits, just like you can't represent 1/3 = 0.333333... exactly with a finite number of decimal digits.
Since 0.1 is slightly more than one tenth, you should expect 48*0.1 to be slightly more than 4.8. And it is:
>>> "%0.40f" % (48*0.1)
'4.8000000000000007105427357601001858711243'
You shouldn't expect 4.8 to equal 4.8 either. It's in fact slightly less than 4.8:
>>> "%0.40f" % (4.8)
'4.7999999999999998223643160599749535322189'
I was wondering if anybody knew of a quick way in python to check and see if a fraction gives a repeating decimal.
I have a small function that takes in two numbers and divides them. If the quotient is a repeating decimal I would like to round to 2 decimal places and if the quotient is not repeating I would like to round to just one
Example:
800/600 = 1.33333333333333 which would equal 1.33
900/600 = 1.5 would stay as 1.5
I know that I need to use the two statements for the two types of rounding
output = "{:.2f}".format(float(num))
output = "{:,}".format(float(num))
but I am having trouble with the if statement to direct to one or the other.
Can anybody help with some insight?
Use the fractions module, which implements exact rational arithmetic:
import fractions
# fractions.Fraction instances are automatically put in lowest terms.
ratio = fractions.Fraction(numerator, denominator)
You can then inspect the denominator of the result:
def is_repeating(fraction):
denom = fraction.denominator
while not (denom % 2):
denom //= 2
while not (denom % 5):
denom //= 5
return denom != 1
Just a workaround using regex :)
import re
result = str(800/600)
# result = str(900/600)
repeating_pair = re.escape(result.split('.')[1][:2])
check_within = result.split('.')[1][2:]
if re.match(repeating_pair, check_within):
print("{:.2f}".format(float(result)))
else:
print("{:.1f}".format(float(result)))
Output:
1.33
And for 900/600
1.5
Try this: Just use brute force. Since you want only 2 decimal places. Just divide and then test it when it is rounded to 0 and 1 decimal place and see where it stops being unique. If it is not unique at this point, then round to 2 decimal places.
def f(x):
if x == round(x,0):
return '{:.0f}'.format(x)
elif x == round(x,1):
return '{:.1f}'.format(x)
else:
return round(x,2)
y = [1, 2, 3, 3/2, 1/9, 8/9, 1/11, 12/11, 10/11, 14/13, 1/3]
for item in y:
print(f(item))
Output:
1
2
3
1.5
0.11
0.89
0.09
1.09
0.91
1.08
0.33
>>>
repeating decimal
There are only 10 fractions that can be written as some repeated digit - .(0), .(1), ... .(9). Thus, if you only care about repeating pattern starting right after decimal point, you only need to check against those cases.
All those numbers (and only them) give an integer if multiplied by 9.
Thus, if (9 * numenator) % denominator == 0, you'll print 2 digits.
You'll probably want to exclude .(0) pattern though. To do that, test if your fraction is in fact an integer - numenator % denominator == 0.
Also check out fractions module in case you have some wheels to reinvent.
Of course, if you only have your number as a float, there is some ambiguity about what numenator and denominator are, because floats don't actually store rational numbers like 1/3. You can experiment with fractions's .limit_denominator() to choose something that works for your case.
This I imagine is extremely simple - but why in the following are the two values for y not == 0? I thought the whole point of the decimal module was to get rid of the float dust ...The following is an extremely simplified version of a mathematical routine that passes numbers around as variables.
from decimal import *
getcontext().prec = 2
q = Decimal(0.01)
x = Decimal(0.10) * Decimal(0.10)
y = Decimal(x) - Decimal(q)
print(x,y, Decimal(y))
'''
x== 0.010
y== -2.1E-19
Decimal(y) == -2.1E-19
'''
Try specifying the numbers as strings
>>> Decimal('0.10') * Decimal('0.10') - Decimal('0.0100')
>>> Decimal('0.000')
The float literal 0.10 is not precisely the mathematical number 0.10, using it to initialize Decimal doesn't avoid the float precision problem.
Instead, using strings to initialize Decimal can give you expected result:
x = Decimal('0.10') * Decimal('0.10')
y = Decimal(x) - Decimal('0.010')
This is a more detailed explanation of the point made in existing answers.
You really do need to get rid of the numeric literals such as 0.1 if you want exact decimal arithmetic. The numeric literals will typically be represented by IEEE 754 64-bit binary floating point numbers.
The closest such number to 0.1 is 0.1000000000000000055511151231257827021181583404541015625. Its square is 0.01000000000000000111022302462515657123851077828659396139564708135883709660962637144621112383902072906494140625, which is not the same as the closest to 0.01, 0.01000000000000000020816681711721685132943093776702880859375.
You can get a clearer view of what is going on by removing the prec =2 context, allowing more precise output:
from decimal import *
q = Decimal(0.01)
x = Decimal(0.10) * Decimal(0.10)
y = Decimal(x) - Decimal(q)
print(q)
print(x)
print(y)
Output:
0.01000000000000000020816681711721685132943093776702880859375
0.01000000000000000111022302463
9.020562075127831486705690622E-19
If you had used string literals, as suggested by the other responses, the conversion to Decimal would have been done directly, without going through binary floating point. Both 0.1 and 0.01 are exactly representable in Decimal, so there would be no rounding error.
The following code snippet is giving 6 as a result:
import math
number = (1 - 0.99) * 500
math.ceil(number)
while the (mathematically) correct answer would be 5. Presumably this is a rounding problem - what is the best way to enforce the correct solution?
Presumably this is a rounding problem
Yes:
>>> 1 - 0.99
0.010000000000000009
>>> (1 - 0.99) * 500
5.000000000000004
what is the best way to enforce the correct solution?
You could use a decimal.Decimal instead of a float:
>>> from decimal import Decimal
>>> import math
>>> (1 - Decimal("0.99")) * 500
Decimal('5.00')
>>> math.ceil((1 - Decimal("0.99")) * 500)
5.0
It's a floating-point error since some numbers can't be represented exactly (infinitely many numbers have to be represented using a finite number of bits -- there has to be some trade-offs). This is why you lose some precision with floating point operations:
>>> 1-0.99
0.010000000000000009
Try Decimal:
>>> from decimal import Decimal as d
>>> result = (1 - d("0.99")) * 500
>>> result
Decimal('5.00')
>>> math.ceil(result)
5.0
Edit
It may look like all the numbers have exact representations:
>>> a = 1.0; b = 0.99; c = 0.01
>>> a, b, c
(1.0, 0.99, 0.01)
So this result might seem surprising:
>>> a - b
0.010000000000000009
>>> a - b == c
False
But it's just the precision and rounding errors that accumulate. Here are the same numbers and calculation, but showing more digits:
>>> def o(f): return "%.30f" % f
>>> o(a)
'1.000000000000000000000000000000'
>>> o(b)
'0.989999999999999991118215802999'
>>> o(c)
'0.010000000000000000208166817117'
>>> o(a-b)
'0.010000000000000008881784197001'
Python 2.7 rounds to 17 significant digits. It is a different model from real math.
The given answers are correct, this is a case of rounding error. However, I think it would be useful to include why this happens.
In hardware, floating point numbers are base 2 (AKA binary). The problem is that most decimal fractions cannot be represented exactly as binary fractions. The translation of that is (in general) floating point numbers are only approximated by the binary floating point numbers actually stored in the machine.