integer to single precision conversion in python - python

I can't figure out how to convert an integer to a single precision using python, I already tried to use numpy but the float32() function doesn't help.
example
984761996 -> 1.360135E-3

this is the code I wrote:
import math
n = 984761996
size = 32
IEEE754 = {16: [5,15],32: [8,127],64: [11,1023],80: [15,16383],128: [15,16383]}
b = bin(n)
b = b[2:].zfill(size)
signal = b[0]
exponent = b[1:IEEE754[size][0]+1]
fraction = b[IEEE754[size][0]+1:]
i=-1
fraction_ten = 0
for c in fraction:
fraction_ten = fraction_ten + int(c)*math.pow(2,i)
i = i - 1
n_ten = math.pow(-1,int(signal)) * (1 + fraction_ten) * math.pow(2,(int(exponent,2)-IEEE754[size][1]))
print "%.6E" % n_ten

Related

OverflowError: int too large to convert to float - Python

i'm working on basic calculus and factorials with python. Trying to produce PI from newton series, but i cant go further than 171 iterations because of this error: OverflowError: int too large to convert to float. Here's the code:
i've imported this: from math import factorial, gamma / from math import sqrt
def calculus(ran):
x = 1/2
exp = 0
p = 0
terminos = []
length = len(terminos)
for i in range(ran):
k = i
n = 1/2
tzero = 1
exp += 2
num = gamma(n)
if k != 0:
den1 = factorial(k)
den2 = n-k
den3 = gamma(den2)
den = den1 * den3
f1 = num/den
f2 = 1/(exp+1)
f3 = x**(exp+1)
terminos.append(f1*f2*f3)
else:
f1 = x
f2 = 1
f3 = 1
terminos.append(f1*f2*f3)
p = 0
terminos.append(-sqrt(3)/8)
serie = sum(terminos)
pi = serie * 12
print(pi)
calculus(172)
According to Python Tutorial in cases where precision is important it's better to use decimal or fractions modules.
For example, instead of writing f2 = 1/(exp+1) you should write
from fractions import Fraction
f2 = Fraction(1, exp+1)
Read this article to get a better understanding.
Note that doing such heavy computations is not recommended in Python itself even with built-in libraries like fractions. You should use libraries such as NumPy for better performance and also better precision.

convert number to scientific notation python with a variable

I want to use str.format to convert 2 number to scientific notation raised to the same exponential but the exponential need to be set off the str.format.
Example:
from math import log10
y=10000
x=round(np.log10(y))
m=10
y="{:e}".format(y)
m="{:e}".format(m)
print(y)
print(m)
here I have that m has e = 1 and y e = 4 and what I want is for both to have the same "e". i want to set both to exponencial x.
I think you have to calculate this yourself, for example using a helper function which returns a string:
def format_exp(x, n):
significand = x / 10 ** n
exp_sign = '+' if n >= 0 else '-'
return f'{significand:f}e{exp_sign}{n:02d}'
Explanation:
x is the number to format, and n is the power that you want to display;
significand calculates the part to show in front of the e by dividing x by 10n (10 ** n);
exp_sign is either + or -, depending on the value of n (to replicate the default behaviour).
Example usage:
>>> import math
>>> y = 10000
>>> m = 10
>>> x = math.floor(math.log10(y)) # x = 4
>>> print(format_exp(y, x))
1.000000e+04
>>> print(format_exp(m, x))
0.001000e+04
>>> print(format_exp(y, 1))
1000.000000e+01
>>> print(format_exp(m, 1))
1.000000e+01
You can increase the complexity of this function by adding an additional parameter d to set the number of decimals printed in the significand part (with a default value of 6 to reproduce the default Python behaviour):
def format_exp(x, n, d=6):
significand = x / 10 ** n
exp_sign = '+' if n >= 0 else '-'
return f'{significand:.{d}f}e{exp_sign}{n:02d}'
With this function, you can control the number of decimals printed:
>>> print(format_exp(y, x)) # default behaviour still works
1.000000e+04
>>> print(format_exp(y, x, 4))
1.0000e+04
>>> print(format_exp(y, x, 1))
1.0e+04

Python Rounding Down to Custom Step

We have a partially working code and 2 examples with different types of custom steps. The example 2 (Int) is working, while the example 1 is not, as it is rounding up instead of down.
import math
def step_size_to_precision(ss):
return ss.find('1') - 1
def format_value(val, step_size_str):
precision = step_size_to_precision(step_size_str)
if precision > 0:
return "{:0.0{}f}".format(val, precision)
return math.floor(int(val))
###########################
# # example 1
step_size = "0.00000100"
quantity = 0.00725562
print(quantity)
print(format_value(quantity, step_size))
# 0.00725562
# 0.007256 <= Is rounding up instead of down. Should be 0.007255
###########################
# # example 2
# step_size = "1"
# quantity = 3.00725562
# print(quantity)
# print(format_value(quantity, step_size))
# returns 3 <= This is correct
###########################
How do we fix it?
You'll want to use Decimal objects to for precise decimal numbers to begin with.
Then, use Decimal.quantize() in the ROUND_DOWN mode.
from decimal import Decimal, ROUND_DOWN
quantity = 0.00725562
step_size = Decimal("0.000001")
print(Decimal(quantity).quantize(step_size, ROUND_DOWN))
prints out
0.007255
Another approach is outlined in this SO answer:
If you want to round down always (instead of rounding to the nearest
precision), then do so, explicitly, with the math.floor()
function:
from math import floor
def floored_percentage(val, digits):
val *= 10 ** (digits + 2)
return '{1:.{0}f}%'.format(digits, floor(val) / 10 ** digits)
print floored_percentage(0.995, 1)
Demo:
>>> from math import floor
>>> def floored_percentage(val, digits):
... val *= 10 ** (digits + 2)
... return '{1:.{0}f}%'.format(digits, floor(val) / 10 ** digits)
...
>>> floored_percentage(0.995, 1)
'99.5%'
>>> floored_percentage(0.995, 2)
'99.50%'
>>> floored_percentage(0.99987, 2)
'99.98%'
For your example:
import math
def step_size_to_precision(ss):
return max(ss.find('1'), 1) - 1
def format_value(val, step_size):
digits = step_size_to_precision(step_size)
val *= 10 ** digits
return '{1:.{0}f}'.format(digits, math.floor(val) / 10 ** digits)
step_size = "0.00000100"
quantity = 0.00725562
print(quantity)
print(format_value(quantity, step_size))
# prints out: 0.007255
A more general approach which allows to round down for step_size which is not only power of 10:
from decimal import Decimal
def floor_step_size(quantity, step_size):
step_size_dec = Decimal(str(step_size))
return float(int(Decimal(str(quantity)) / step_size_dec) * step_size_dec)
Usage:
>>> floor_step_size(0.00725562, "0.00000100")
0.007255
>>> floor_step_size(3.00725562, "1")
3.0
>>> floor_step_size(2.6, "0.25")
2.5
>>> floor_step_size(0.9, "0.2")
0.8

working with large numbers in the fraction module in Python

EDIT: solved but since the solution was in the comments and I cant accept my own solution reffering to the comment till tomorrow it is still open. Once again a big thank you to this great community and its people
optional context: I am computing sollutions for the Pell equation
http://mathworld.wolfram.com/PellEquation.html
On the buttom of the page is a table with values for D -> x, y.
My code works perfectly for EVERY VALUE EXCEPT D = 61. I believe it could have something to do with the values of x and y being very big and maybe the fraction module cant handle such big numbers and there is an overflow?
I made the observation, that whether I give my input/ starting value as a fraction or a decimal changes my solution (but only for D = 61).
Why is my code failing with the value of D = 61? What do I need to change/use to get it to work? Thank you very much for your time and help.
code:
from math import sqrt, floor
from fractions import Fraction
def continued_fraction(D):
# to make sure it is not a problem on converting decimals to fractions I made EVERYTHING a fraction (which shouldnt and didnt affect the output)
# input is the value for D, output is a tuple with (x, y)
D = Fraction(sqrt(D))
aS = []
a0 = D
r1 = Fraction(D - floor(D))
a = Fraction(a0 - r1)
r = Fraction(-1)
count = 0
while a <= 2*floor(D):
aS.append((a, count))
if a == 2*floor(D):
if count % 2 == 0:
break
else:
r = count
if count == 2*r:
break
try:
a0 = Fraction(1/r1)
except ZeroDivisionError:
break
r1 = Fraction(a0 - floor(a0))
a = Fraction(a0 - r1)
count += 1
pS = []
qS = []
a0 = Fraction(floor(D))
p0 = a0
p1 = Fraction(a0 * aS[1][0] + 1)
q0 = Fraction(1)
q1 = Fraction(aS[1][0])
count = 2
while count < len(aS):
pS.append((p0, count - 2))
qS.append((q0, count - 2))
pn = Fraction(aS[count][0] * p1 + p0)
qn = Fraction(aS[count][0] * q1 + q0)
p0 = Fraction(p1)
p1 = Fraction(pn)
q0 = Fraction(q1)
q1 = Fraction(qn)
count += 1
pS.append((p0, count-1))
#pS.append((p1, count))
qS.append((q0, count - 1))
#qS.append((q1, count))
#print(pS)
#print(qS)
return Fraction(pS[-1][0]), Fraction(qS[-1][0])
print(continued_fraction(Fraction(61)))
Fraction(1/r1) means to compute the reciprocal of r1 as an inexact floating-point number, and then find a rational approximation of that inexact number. You want Fraction(1, r1) to directly specify the numerator and denominator of your fraction, without any approximation errors creeping in.
A big thanks to GalAbra and jasonharper for your responds. After knowing with certainty, that it is a percision problem (thank you GalAbra) I knew I needed more decimals for the sqrt(D). I used the decimal module from Python:
from decimal import *
getcontext().prec = 1000
D = Fraction(Decimal(D).sqrt())
with this and the change suggested by jasonharper (thank you again) it works now.

Why is the computing of the value of pi using the Machin Formula giving a wrong value?

For my school project I was trying to compute the value of using different methods. One of the formula I found was the Machin Formula that can be calculated using the Taylor expansion of arctan(x).
I wrote the following code in python:
import decimal
count = pi = a = b = c = d = val1 = val2 = decimal.Decimal(0) #Initializing the variables
decimal.getcontext().prec = 25 #Setting percision
while (decimal.Decimal(count) <= decimal.Decimal(100)):
a = pow(decimal.Decimal(-1), decimal.Decimal(count))
b = ((decimal.Decimal(2) * decimal.Decimal(count)) + decimal.Decimal(1))
c = pow(decimal.Decimal(1/5), decimal.Decimal(b))
d = (decimal.Decimal(a) / decimal.Decimal(b)) * decimal.Decimal(c)
val1 = decimal.Decimal(val1) + decimal.Decimal(d)
count = decimal.Decimal(count) + decimal.Decimal(1)
#The series has been divided into multiple small parts to reduce confusion
count = a = b = c = d = decimal.Decimal(0) #Resetting the variables
while (decimal.Decimal(count) <= decimal.Decimal(10)):
a = pow(decimal.Decimal(-1), decimal.Decimal(count))
b = ((decimal.Decimal(2) * decimal.Decimal(count)) + decimal.Decimal(1))
c = pow(decimal.Decimal(1/239), decimal.Decimal(b))
d = (decimal.Decimal(a) / decimal.Decimal(b)) * decimal.Decimal(c)
val2 = decimal.Decimal(val2) + decimal.Decimal(d)
count = decimal.Decimal(count) + decimal.Decimal(1)
#The series has been divided into multiple small parts to reduce confusion
pi = (decimal.Decimal(16) * decimal.Decimal(val1)) - (decimal.Decimal(4) * decimal.Decimal(val2))
print(pi)
The problem is that I am getting the right value of pi only till 15 decimal places, no matter the number of times the loop repeats itself.
For example:
at 11 repetitions of the first loop
pi = 3.141592653589793408632493
at 100 repetitions of the first loop
pi = 3.141592653589793410703296
I am not increasing the repetitions of the second loop as arctan(1/239) is very small and reaches an extremely small value with a few repetitions and therefore should not affect the value of pi at only 15 decimal places.
EXTRA INFORMATION:
The Machin Formula states that:
π = (16 * Summation of (((-1)^n) / 2n+1) * ((1/5)^(2n+1))) - (4 * Summation of (((-1)^n) / 2n+1) * ((1/239)^(2n+1)))
That many terms is enough to get you over 50 decimal places. The problem is that you are mixing Python floats with Decimals, so your calculations are polluted with the errors in those floats, which are only precise to 53 bits (around 15 decimal digits).
You can fix that by changing
c = pow(decimal.Decimal(1/5), decimal.Decimal(b))
to
c = pow(1 / decimal.Decimal(5), decimal.Decimal(b))
or
c = pow(decimal.Decimal(5), decimal.Decimal(-b))
Obviously, a similar change needs to be made to
c = pow(decimal.Decimal(1/239), decimal.Decimal(b))
You could make your code a lot more readable. For starters, you should put the stuff that calculates the arctan series into a function, rather than duplicating it for arctan(1/5) and arctan(1/239).
Also, you don't need to use Decimal for everything. You can just use simple Python integers for things like count and a. Eg, your calculation for a can be written as
a = (-1) ** count
or you could just set a to 1 outside the loop and negate it each time through the loop.
Here's a more compact version of your code.
import decimal
decimal.getcontext().prec = 60 #Setting precision
def arccot(n, terms):
base = 1 / decimal.Decimal(n)
result = 0
sign = 1
for b in range(1, 2*terms, 2):
result += sign * (base ** b) / b
sign = -sign
return result
pi = 16 * arccot(5, 50) - 4 * arccot(239, 11)
print(pi)
output
3.14159265358979323846264338327950288419716939937510582094048
The last 4 digits are rubbish, but the rest are fine.

Categories

Resources