Python: Solution for high int-precision needed (generate primes) - python

at the moment I try to implement a generate_random_prime()-function from the algorithm shown in FIPS186-4 from NIST (Appendix B3.2.1), see here.
But there seems a big problem with step 4.4 (if p < sqrt(2)*(2**((nlen/2)-1)), because of the precision in Python.
to show the relevant part and problem of my code, see this example:
import os
from decimal import Decimal
import math
for i in range(100):
nlen = 2048 #my key-size should be 2048bit
p = int.from_bytes(os.urandom(int(2048/2/8)), byteorder = "little") #see Ann1 and Ann2
print(p < Decimal(math.sqrt(2))*(Decimal(2**(int(2048/2))) - 1)
Ann1: 2048/2/8 because of bytes
Ann2: I know that os.urandom is not the best generator - I will later use an approved one... for the testing phase it should be acceptable I think...
The result is always "True" - so the algorithm will never leave step 4.4.
I think the problem is Decimal(math.sqrt(2))*(Decimal(2**(int(2048/2))) - 1), because the result of this is Decimal('2.542322012307292741109308792E+308'). Convert to int via int(Decimal(math.sqrt(2))*(Decimal(2**(int(2048/2))) - 1)), the result will be
254232201230729274110930879200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
It is rounded up! - Is this the reason for the always True result? I think in this case it will never be possible to get a p less than Decimal(math.sqrt(2))*(Decimal(2**(int(2048/2))) - 1)
How can I solve this problem?
__
edit: found a mistake:
Decimal(math.sqrt(2))*(Decimal(2**(int(2048/2))) - 1) should be Decimal(math.sqrt(2))*(Decimal(2**(int(2048/2-1)))), so the result of this should be Decimal('1.271161006153646370554654396E+308') instead of Decimal('2.542322012307292741109308791E+308')

You are constantly converting between floats, integers and Decimal. Drop all use of float; this includes not using functions that produce float values, such as math.sqrt().
Stick to Decimal objects instead, and only convert the final value to an integer:
int(Decimal(2).sqrt() * 2 ** ((nlen // 2) - 1))
Note the use of //, to use integer division, not true division (producing floats again).

Related

Hexadecimal notation of square roots in Python - Sha-512

I am going over the description of Sha-512. It is mentioned that the initial hash value consists of the sequence of 64-bit words that are obtained by taking the fractional part of the first eight primes. I am trying to replicate these values in Python, but I am not getting the same results. To include more digits, I am using the mpmath library.
from mpmath import *
mp.dps = 50
sqrt(2)
# mpf('1.4142135623730950488016887242096980785696718753769468')
mpf(0.4142135623730950488016887242096980785696718753769468 * 2 ** 64)
# mpf('7640891576956012544.0')
hex(7640891576956012544)
# '0x6a09e667f3bcc800'
However, the description indicates this value must be 6a09e667f3bcc908. As it can be seen, the result I get differs in the last three digits from what I should be getting according to the description. I was wondering why that is the case, and what is the correct approach.
I have come across a similar question, but adjusting it for 64-bit word would yield:
import math
hex(int(math.modf(math.sqrt(2))[0]*(1<<64)))
# '0x6a09e667f3bcd000'
which actually differs in the last four digits.
As a comment already explained, you're actually only using 53 bits in your calculations (native CPython float precision).
Here's an easy way to reproduce the result you're apparently after:
>>> import decimal
>>> x = decimal.getcontext().sqrt(2) - 1
>>> x
Decimal('0.414213562373095048801688724')
>>> hex(int(x * 2**64))
'0x6a09e667f3bcc908'
Nothing really magical about decimal. It just happens to use enough precision by default. You could certainly do the same with mpmath.
For example,
>>> import mpmath
>>> mpmath.mp.prec = 80
>>> hex(int(mpmath.frac( mpmath.sqrt(2) ) * 2**64))
'0x6a09e667f3bcc908'

Math.tan for small angles. Does python use small angle approximation?

I am trying to compute math.tan(0.000000001) and I am getting 0.00000001
>>> math.tan(0.00000001) == 0.00000001
True
Is this due to how math.tan is implemented? Does it use small-angle approximation?
Where can I get more documentation about this
One way to go would be, by analogy with numpy.expm1, to implement a function that computes tan(x)-x in double precision.
While a production quality version of that night be tricky, here is a simple version, that should give accurate answers for |x| < 1e-6
tan(x)-x = sin(x)/cos(x) - x = (sin(x)-x*cos(x))/cos(x)
for such small x we can write, to better than double precision
sin(x) = x - x*x*x/6 + x*x*x*x*x/120
cos(x) = 1 - x*x/2 + x*x*x*x/24
Substituting these we get
tan(x)-x = x*x*x*(1.0/3 - (1.0/30)*x*x)/cos(x)
There's nothing special about this. Python's float only has limited precision, which we can explore with numpy:
0.000000010000000000000000209226 # np.tan(0.00000001)
0.000000009999999999999998554864 # np.nextafter(np.tan(0.00000001), -1)
0.000000010000000000000001863587 # np.nextafter(np.tan(0.00000001), 1)
0.000000010000000000000000333... # True value
From this we can see that 0.000000010000000000000000209226 is the closest representation to the true value, but also that it's safe to round-trip this to 0.00000001, thus Python chooses to print it that way.

I'm making mistakes dividing large numbers

I am trying to write a program in python 2.7 that will first see if a number divides the other evenly, and if it does get the result of the division.
However, I am getting some interesting results when I use large numbers.
Currently I am using:
from __future__ import division
import math
a=82348972389472433334783
b=2
if a/b==math.trunc(a/b):
answer=a/b
print 'True' #to quickly see if the if loop was invoked
When I run this I get:
True
But 82348972389472433334783 is clearly not even.
Any help would be appreciated.
That's a crazy way to do it. Just use the remainder operator.
if a % b == 0:
# then b divides a evenly
quotient = a // b
The true division implicitly converts the input to floats which don't provide the precision to store the value of a accurately. E.g. on my machine
>>> int(1E15+1)
1000000000000001
>>> int(1E16+1)
10000000000000000
hence you loose precision. A similar thing happens with your big number (compare int(float(a))-a).
Now, if you check your division, you see the result "is" actually found to be an integer
>>> (a/b).is_integer()
True
which is again not really expected beforehand.
The math.trunc function does something similar (from the docs):
Return the Real value x truncated to an Integral (usually a long integer).
The duck typing nature of python allows a comparison of the long integer and float, see
Checking if float is equivalent to an integer value in python and
Comparing a float and an int in Python.
Why don't you use the modulus operator instead to check if a number can be divided evenly?
n % x == 0

Converting An "Infinite" Float To An Int [duplicate]

This question already has answers here:
Integer square root in python
(14 answers)
Closed 8 years ago.
I'm trying to check if a number is a perfect square. However, i am dealing with extraordinarily large numbers so python thinks its infinity for some reason. it gets up to 1.1 X 10^154 before the code returns "Inf". Is there anyway to get around this? Here is the code, the lst variable just holds a bunch of really really really really really big numbers
import math
from decimal import Decimal
def main():
for i in lst:
root = math.sqrt(Decimal(i))
print(root)
if int(root + 0.5) ** 2 == i:
print(str(i) + " True")
Replace math.sqrt(Decimal(i)) with Decimal(i).sqrt() to prevent your Decimals decaying into floats
I think that you need to take a look at the BigFloat module, e.g.:
import bigfloat as bf
b = bf.BigFloat('1e1000', bf.precision(21))
print bf.sqrt(b)
Prints BigFloat.exact('9.9999993810013282e+499', precision=53)
#casevh has the right answer -- use a library that can do math on arbitrarily large integers. Since you're looking for squares, you presumably are working with integers, and one could argue that using floating point types (including decimal.Decimal) is, in some sense, inelegant.
You definitely shouldn't use Python's float type; it has limited precision (about 16 decimal places). If you do use decimal.Decimal, be careful to specify the precision (which will depend on how big your numbers are).
Since Python has a big integer type, one can write a reasonably simple algorithm to check for squareness; see my implementation of such an algorithm, along with illustrations of problems with float, and how you could use decimal.Decimal, below.
import math
import decimal
def makendigit(n):
"""Return an arbitraryish n-digit number"""
return sum((j%9+1)*10**i for i,j in enumerate(range(n)))
x=makendigit(30)
# it looks like float will work...
print 'math.sqrt(x*x) - x: %.17g' % (math.sqrt(x*x) - x)
# ...but actually they won't
print 'math.sqrt(x*x+1) - x: %.17g' % (math.sqrt(x*x+1) - x)
# by default Decimal won't be sufficient...
print 'decimal.Decimal(x*x).sqrt() - x:',decimal.Decimal(x*x).sqrt() - x
# ...you need to specify the precision
print 'decimal.Decimal(x*x).sqrt(decimal.Context(prec=30)) - x:',decimal.Decimal(x*x).sqrt(decimal.Context(prec=100)) - x
def issquare_decimal(y,prec=1000):
x=decimal.Decimal(y).sqrt(decimal.Context(prec=prec))
return x==x.to_integral_value()
print 'issquare_decimal(x*x):',issquare_decimal(x*x)
print 'issquare_decimal(x*x+1):',issquare_decimal(x*x+1)
# you can check for "squareness" without going to floating point.
# one option is a bisection search; this Newton's method approach
# should be faster.
# For "industrial use" you should use gmpy2 or some similar "big
# integer" library.
def isqrt(y):
"""Find largest integer <= sqrt(y)"""
if not isinstance(y,(int,long)):
raise ValueError('arg must be an integer')
if y<0:
raise ValueError('arg must be positive')
if y in (0,1):
return y
x0=y//2
while True:
# newton's rule
x1= (x0**2+y)//2//x0
# we don't always get converge to x0=x1, e.g., for y=3
if abs(x1-x0)<=1:
# nearly converged; find biggest
# integer satisfying our condition
x=max(x0,x1)
if x**2>y:
while x**2>y:
x-=1
else:
while (x+1)**2<=y:
x+=1
return x
x0=x1
def issquare(y):
"""Return true if non-negative integer y is a perfect square"""
return y==isqrt(y)**2
print 'isqrt(x*x)-x:',isqrt(x*x)-x
print 'issquare(x*x):',issquare(x*x)
print 'issquare(x*x+1):',issquare(x*x+1)
math.sqrt() converts the argument to a Python float which has a maximum value around 10^308.
You should probably look at using the gmpy2 library. gmpy2 provide very fast multiple precision arithmetic.
If you want to check for arbitrary powers, the function gmpy2.is_power() will return True if a number is a perfect power. It may be a cube or fifth power so you will need to check for power you are interested in.
>>> gmpy2.is_power(456789**372)
True
You can use gmpy2.isqrt_rem() to check if it is an exact square.
>>> gmpy2.isqrt_rem(9)
(mpz(3), mpz(0))
>>> gmpy2.isqrt_rem(10)
(mpz(3), mpz(1))
You can use gmpy2.iroot_rem() to check for arbitrary powers.
>>> gmpy2.iroot_rem(13**7 + 1, 7)
(mpz(13), mpz(1))

Million decimal places in Python

We recently delve into infinite series in calculus and that being said, I'm having so much fun with it. I derived my own inverse tan infinte series in python and set to 1 to get pi/4*4 to get pi. I know it's not the fastest algorithm, so please let's not discuss about my algorithm. What I would like to discuss is how do I represent very very small numbers in python. What I notice is as my programs iterate the series, it stops somewhere at the 20 decimal places (give or take). I tried using decimal module and that only pushed to about 509. I want an infinite (almost) representation.
Is there a way to do such thing? I reckon no data type will be able to handle such immensity, but if you can show me a way around that, I would appreciate that very much.
Python's decimal module requires that you specify the "context," which affects how precise the representation will be.
I might recommend gmpy2 for this type of thing - you can do the calculation on rational numbers (arbitrary precision) and convert to decimal at the last step.
Here's an example - substitute your own algorithm as needed:
import gmpy2
# See https://gmpy2.readthedocs.org/en/latest/mpfr.html
gmpy2.get_context().precision = 10000
pi = 0
for n in range(1000000):
# Formula from http://en.wikipedia.org/wiki/Calculating_pi#Arctangent
numer = pow(2, n + 1)
denom = gmpy2.bincoef(n + n, n) * (n + n + 1)
frac = gmpy2.mpq(numer, denom)
pi += frac
# Print every 1000 iterations
if n % 1000 == 0:
print(gmpy2.mpfr(pi))

Categories