square root of a number greater than 10^2000 in Python 3 - python

I'd like to calculate the square root of a number bigger than 10^2000 in Python. If I treat this number like a normal integer, I will always get this result back:
Traceback (most recent call last):
File "...", line 3, in <module>
print( q*(0.5) )
OverflowError: int too large to convert to float
How do I fix this? Or does a possibilty other than using Python exist to calculate this square root?

Just use the decimal module:
>>> from decimal import *
>>> Decimal(10**2000).sqrt()
Decimal('1.000000000000000000000000000E+1000')
>>> Decimal(10**200000).sqrt()
Decimal('1.000000000000000000000000000E+100000')
>>> Decimal(15**35315).sqrt()
Decimal('6.782765081358674922386659760E+20766')
You can also use the gmpy2 library.
>>> import gmpy2
>>> n = gmpy2.mpz(99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999982920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000726067)
>>> gmpy2.get_context().precision=2048
>>> x = gmpy2.sqrt(n)
Useful links:
Decimal - Python Documentation

The usual square root methods convert the parameter to a float value before doing the calculation. As you saw, this does not work well with very large integers.
So use a function that is designed to work on arbitrarily large integers. Here is one, guaranteed to return correct integer part of the square root of any positive integer. This function drops the fractional part of the result, which may or may not be what you want. Since this function uses iteration it is also slower than the built-in square root routines. The Decimal module works on larger integers than the built-in routines but the precision of the values must be defined in advance so it does not work on arbitrarily large values.
import math
_1_50 = 1 << 50 # 2**50 == 1,125,899,906,842,624
def isqrt(x):
"""Return the integer part of the square root of x, even for very
large integer values."""
if x < 0:
raise ValueError('square root not defined for negative numbers')
if x < _1_50:
return int(math.sqrt(x)) # use math's sqrt() for small parameters
n = int(x)
if n <= 1:
return n # handle sqrt(0)==0, sqrt(1)==1
# Make a high initial estimate of the result (a little lower is slower!!!)
r = 1 << ((n.bit_length() + 1) >> 1)
while True:
newr = (r + n // r) >> 1 # next estimate by Newton-Raphson
if newr >= r:
return r
r = newr

When using sqrt from the library math, before it proceeds to square root it, it will convert the value to a float.
If we manually try to convert the 10**2000 to a float, it also triggers an error
>>> float(10**2000)
---------------------------------------------------------------------------
OverflowError Traceback (most recent call last)
<ipython-input-14-6ac81f63106d> in <module>
----> 1 math.sqrt(10**2000)
OverflowError: int too large to convert to float
If we were speaking of a big number, but with the square equals or less than 308, the Decimal module would do the work as follows
>>> from decimal import Decimal
>>> Decimal(math.sqrt(10**308))
Decimal('10000000000000000369475456880582265409809179829842688451922778552150543659347219597216513109705408327446511753687232667314337003349573404171046192448274432')
However, as the number is way square is way bigger than 308, in this case, 2000, one would have to do as follows
>>> from decimal import Decimal
>>> Decimal(10**2000).sqrt()
Decimal('1.000000000000000000000000000E+1000')
Let's see the output if one tries to convert the Decimal(10**2000) to float
>>> float(Decimal(10**2000))
inf
One might also use the decimal module when working with factorials, as they tend to get large really fast.

Related

How can I check the length of a long float? Python is truncating the length [duplicate]

I have some number 0.0000002345E^-60. I want to print the floating point value as it is.
What is the way to do it?
print %f truncates it to 6 digits. Also %n.nf gives fixed numbers. What is the way to print without truncation.
Like this?
>>> print('{:.100f}'.format(0.0000002345E-60))
0.0000000000000000000000000000000000000000000000000000000000000000002344999999999999860343602938602754
As you might notice from the output, it’s not really that clear how you want to do it. Due to the float representation you lose precision and can’t really represent the number precisely. As such it’s not really clear where you want the number to stop displaying.
Also note that the exponential representation is often used to more explicitly show the number of significant digits the number has.
You could also use decimal to not lose the precision due to binary float truncation:
>>> from decimal import Decimal
>>> d = Decimal('0.0000002345E-60')
>>> p = abs(d.as_tuple().exponent)
>>> print(('{:.%df}' % p).format(d))
0.0000000000000000000000000000000000000000000000000000000000000000002345
You can use decimal.Decimal:
>>> from decimal import Decimal
>>> str(Decimal(0.0000002345e-60))
'2.344999999999999860343602938602754401109865640550232148836753621775217856801120686600683401464097113374472942165409862789978024748827516129306833728589548440037314681709534891496105046826414763927459716796875E-67'
This is the actual value of float created by literal 0.0000002345e-60. Its value is a number representable as python float which is closest to actual 0.0000002345 * 10**-60.
float should be generally used for approximate calculations. If you want accurate results you should use something else, like mentioned Decimal.
If I understand, you want to print a float?
The problem is, you cannot print a float.
You can only print a string representation of a float. So, in short, you cannot print a float, that is your answer.
If you accept that you need to print a string representation of a float, and your question is how specify your preferred format for the string representations of your floats, then judging by the comments you have been very unclear in your question.
If you would like to print the string representations of your floats in exponent notation, then the format specification language allows this:
{:g} or {:G}, depending whether or not you want the E in the output to be capitalized). This gets around the default precision for e and E types, which leads to unwanted trailing 0s in the part before the exponent symbol.
Assuming your value is my_float, "{:G}".format(my_float) would print the output the way that the Python interpreter prints it. You could probably just print the number without any formatting and get the same exact result.
If your goal is to print the string representation of the float with its current precision, in non-exponentiated form, User poke describes a good way to do this by casting the float to a Decimal object.
If, for some reason, you do not want to do this, you can do something like is mentioned in this answer. However, you should set 'max_digits' to sys.float_info.max_10_exp, instead of 14 used in the answer. This requires you to import sys at some point prior in the code.
A full example of this would be:
import math
import sys
def precision_and_scale(x):
max_digits = sys.float_info.max_10_exp
int_part = int(abs(x))
magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1
if magnitude >= max_digits:
return (magnitude, 0)
frac_part = abs(x) - int_part
multiplier = 10 ** (max_digits - magnitude)
frac_digits = multiplier + int(multiplier * frac_part + 0.5)
while frac_digits % 10 == 0:
frac_digits /= 10
scale = int(math.log10(frac_digits))
return (magnitude + scale, scale)
f = 0.0000002345E^-60
p, s = precision_and_scale(f)
print "{:.{p}f}".format(f, p=p)
But I think the method involving casting to Decimal is probably better, overall.

Parsing Large Numbers

I am writing some simple code to raise a base value to a power
then perform some operations on the output.
I have included the code I am using now, below ( see end of this message ), also see immediately below what this looks like when I run my script from the console :
.........................................
C:\PYTHON34>python tst.py
INPUT Value: 431.1
INPUT Power Value; 1.9907
RESULT 1739.554505641426658257842063903808593750000000000000000000000000
.........................................
This is the code I am currently using :
import time
e0=time.time()
c0=time.clock()
import sys
import math
from sympy import mpmath
from mpmath import *
mpmath.mp.dps = 10000
inputx = float(input('Enter inputx Value: '))
powerx =float(input('Enter Power Value; '))
inputx_squared = float((mpmath.power(inputx, powerx)))%1999
print('\r')
print('RESULT ', '%.60f' % inputx_squared)
elapsed_time=time.time() -e0
cpu_time=time.clock() -c0
print('\r')
print("CPU TIME ;", cpu_time)
What I need to be able to do ;
1.) Store whole number value to left of the decimal point without decimals to a variable = x
2.) Grab entire decimal value to the right of the decimal point and store in a variable = y
Parse (y) according to some simple rules. Here's where it gets trick for me.
What I want to do is examine (y) to see if there are any leading leading and trailing zeros
In the example ; "1739.554505....." IF this value was instead, something like any of the following ;
1739.0554505
1739.00554505
1739.000554505
Then I want to extract the whole number less any continuous leading zeroes
NEXT, I want to cut the number so that when there are four continuous trailing zeros, all zeros starting from the first one that started off the first four continuous zeros and all following zeroes are
truncated
So in our example ;
"1739.554505641426658257842063903808593750000000000000000000000000"
(y) becomes "55450564142665825784206390380859375"
Next I want to take the mod of above value by %1999
This returns "1407"
Next I want to join this value AS the decimal value to the right as ;
1739.1407
I agree with the first comment and would recommend using strings.
Result = 1739.554505641426658257842063903808593750000000000000000000000000
z = str(Result).split(".")
x = z[0]
y = z[1].strip("0")
mode = int(y)%1999
new_res = float(x+"."+str(mode))
print(new_res)
>>>1739.1407
The strip() method removes all leading and trailing zeros.
And I am also interested in the application of such operations.
Have you considered using the Decimal type:
import math
from decimal import Decimal, getcontext
getcontext().prec = 60
inputx = Decimal('431.1')
powerx = Decimal('1.9907')
inputx_squared = (inputx ** powerx) % 1999
x = math.floor(inputx_squared)
y = inputx_squared - x
which gives you
In: x
Out: 1739
In: y
Out: Decimal('0.554505641528269687606334953784096474037969748439285550')

Math.pow vs ** casted as a Decimal in Python?

So I was writing a simple script to demonstrate geometric series convergence.
from decimal import *
import math
initial = int(input("a1? "))
r = Decimal(input("r? "))
runtime = int(input("iterations? "))
sum_value=0
for i in range(runtime):
sum_value+=Decimal(initial * math.pow(r,i))
print(sum_value)
When I use values such as:
a1 = 1
r = .2
iterations = 100000
I get the convergence to be 1.250000000000000021179302083
When I replace the line:
sum_value+=Decimal(initial * math.pow(r,i))
With:
sum_value+=Decimal(initial * r ** i)
I get a more precise value, 1.250000000000000000000000002
What exactly is the difference here? From my understanding, it has to do with math.pow being a floating point operation, but I would just think that ** is syntactic sugar for the math power function. If they are indeed different, then why with a precision value of 200, when inputting the following to IDLE:
>>> Decimal(.8**500)
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')
>>> Decimal(math.pow(.8,500))
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')
They seem to be exactly the same. What is happening here?
The difference is, as you imply, that math.pow() converts the inputs to floats as stated in the documentation: "Unlike the built-in ** operator, math.pow() converts both its arguments to type float."
Therefore math.pow() also delivers a float as answer, independently of whether the input is Decimal (or int) or whatever. When using numbers that are not exactly representable as a float(but is as Decimal) you are likely to get a more precise answer using the ** operator.
This explains why your loop gives a more exact result in case of using ** since you are working with Decimal numbers raised to an integer. In the second case, you are inadvertently using floats for both calculations and then converting the result to Decimal when the operation is already executed. If you instead work with explicit Decimal values you will see the difference:
>>> Decimal('.8')**500
Decimal('3.507466211043403874762758796E-49')
>>> Decimal(math.pow(Decimal('.8'), 500))
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')
Thus, in the second case, the Decimal value is automatically casted to a float and the result is the same as for your example above. In the first case, however, the calculation is executed in the Decimal domain and yields a slightly different result.

How to convert a string representing a binary fraction to a number in Python

Let us suppose that we have a string representing a binary fraction such as:
".1"
As a decimal number this is 0.5. Is there a standard way in Python to go from such strings to a number type (whether it is binary or decimal is not strictly important).
For an integer, the solution is straightforward:
int("101", 2)
>>>5
int() takes an optional second argument to provide the base, but float() does not.
I am looking for something functionally equivalent (I think) to this:
def frac_bin_str_to_float(num):
"""Assuming num to be a string representing
the fractional part of a binary number with
no integer part, return num as a float."""
result = 0
ex = 2.0
for c in num:
if c == '1':
result += 1/ex
ex *= 2
return result
I think that does what I want, although I may well have missed some edge cases.
Is there a built-in or standard method of doing this in Python?
The following is a shorter way to express the same algorithm:
def parse_bin(s):
return int(s[1:], 2) / 2.**(len(s) - 1)
It assumes that the string starts with the dot. If you want something more general, the following will handle both the integer and the fractional parts:
def parse_bin(s):
t = s.split('.')
return int(t[0], 2) + int(t[1], 2) / 2.**len(t[1])
For example:
In [56]: parse_bin('10.11')
Out[56]: 2.75
It is reasonable to suppress the point instead of splitting on it, as follows. This bin2float function (unlike parse_bin in previous answer) correctly deals with inputs without points (except for returning an integer instead of a float in that case).
For example, the invocations bin2float('101101'), bin2float('.11101'), andbin2float('101101.11101')` return 45, 0.90625, 45.90625 respectively.
def bin2float (b):
s, f = b.find('.')+1, int(b.replace('.',''), 2)
return f/2.**(len(b)-s) if s else f
You could actually generalize James's code to convert it from any number system if you replace the hard coded '2' to that base.
def str2float(s, base=10):
dot, f = s.find('.') + 1, int(s.replace('.', ''), base)
return f / float(base)**(len(s) - dot) if dot else f
You can use the Binary fractions package. With this package you can convert binary-fraction strings into floats and vice-versa.
Example:
>>> from binary_fractions import Binary
>>> float(Binary("0.1"))
0.5
>>> str(Binary(0.5))
'0b0.1'
It has many more helper functions to manipulate binary strings such as: shift, add, fill, to_exponential, invert...
PS: Shameless plug, I'm the author of this package.

Operations for Long and Float in Python

I'm trying to compute this:
from scipy import *
3600**3400 * (exp(-3600)) / factorial(3400)
the error: unsupported long and float
Try using logarithms instead of working with the numbers directly. Since none of your operations are addition or subtraction, you could do the whole thing in logarithm form and convert back at the end.
Computing with numbers of such magnitude, you just can't use ordinary 64-bit-or-so floats, which is what Python's core runtime supports. Consider gmpy (do not get the sourceforge version, it's aeons out of date) -- with that, math, and some care...:
>>> e = gmpy.mpf(math.exp(1))
>>> gmpy.mpz(3600)**3400 * (e**(-3600)) / gmpy.fac(3400)
mpf('2.37929475533825366213e-5')
(I'm biased about gmpy, of course, since I originated and still participate in that project, but I'd never make strong claims about its floating point abilities... I've been using it mostly for integer stuff... still, it does make this computation possible!-).
You could try using the Decimal object. Calculations will be slower but you won't have trouble with really small numbers.
from decimal import Decimal
I don't know how Decimal interacts with the scipy module, however.
This numpy discussion might be relevant.
Well the error is coming about because you are trying to multiply
3600**3400
which is a long with
exp(-3600)
which is a float.
But regardless, the error you are receiving is disguising the true problem. It seems exp(-3600) is too big a number to fit in a float anyway. The python math library is fickle with large numbers, at best.
exp(-3600) is too smale, factorial(3400) is too large:
In [1]: from scipy import exp
In [2]: exp(-3600)
Out[2]: 0.0
In [3]: from scipy import factorial
In [4]: factorial(3400)
Out[4]: array(1.#INF)
What about calculate it step by step as a workaround(and it makes sense
to check the smallest and biggest intermediate result):
from math import exp
output = 1
smallest = 1e100
biggest = 0
for i,j in izip(xrange(1, 1701), xrange(3400, 1699, -1)):
output = output * 3600 * exp(-3600/3400) / i
output = output * 3600 * exp(-3600/3400) / j
smallest = min(smallest, output)
biggest = max(biggest, output)
print "output: ", output
print "smallest: ", smallest
print "biggest: ", biggest
output is:
output: 2.37929475534e-005
smallest: 2.37929475534e-005
biggest: 1.28724174494e+214

Categories

Resources