I want to generate the digits of the square root of two to 3 million digits.
I am aware of Newton-Raphson but I don't have much clue how to implement it in C or C++ due to lack of biginteger support. Can somebody point me in the right direction?
Also, if anybody knows how to do it in python (I'm a beginner), I would also appreciate it.
You could try using the mapping:
a/b -> (a+2b)/(a+b) starting with a= 1, b= 1. This converges to sqrt(2) (in fact gives the continued fraction representations of it).
Now the key point: This can be represented as a matrix multiplication (similar to fibonacci)
If a_n and b_n are the nth numbers in the steps then
[1 2] [a_n b_n]T = [a_(n+1) b_(n+1)]T
[1 1]
which now gives us
[1 2]n [a_1 b_1]T = [a_(n+1) b_(n+1)]T
[1 1]
Thus if the 2x2 matrix is A, we need to compute An which can be done by repeated squaring and only uses integer arithmetic (so you don't have to worry about precision issues).
Also note that the a/b you get will always be in reduced form (as gcd(a,b) = gcd(a+2b, a+b)), so if you are thinking of using a fraction class to represent the intermediate results, don't!
Since the nth denominators is like (1+sqrt(2))^n, to get 3 million digits you would likely need to compute till the 3671656th term.
Note, even though you are looking for the ~3.6 millionth term, repeated squaring will allow you to compute the nth term in O(Log n) multiplications and additions.
Also, this can easily be made parallel, unlike the iterative ones like Newton-Raphson etc.
EDIT: I like this version better than the previous. It's a general solution that accepts both integers and decimal fractions; with n = 2 and precision = 100000, it takes about two minutes. Thanks to Paul McGuire for his suggestions & other suggestions welcome!
def sqrt_list(n, precision):
ndigits = [] # break n into list of digits
n_int = int(n)
n_fraction = n - n_int
while n_int: # generate list of digits of integral part
ndigits.append(n_int % 10)
n_int /= 10
if len(ndigits) % 2: ndigits.append(0) # ndigits will be processed in groups of 2
decimal_point_index = len(ndigits) / 2 # remember decimal point position
while n_fraction: # insert digits from fractional part
n_fraction *= 10
ndigits.insert(0, int(n_fraction))
n_fraction -= int(n_fraction)
if len(ndigits) % 2: ndigits.insert(0, 0) # ndigits will be processed in groups of 2
rootlist = []
root = carry = 0 # the algorithm
while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
carry = carry * 100
if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
x = 9
while (20 * root + x) * x > carry:
x -= 1
carry -= (20 * root + x) * x
root = root * 10 + x
rootlist.append(x)
return rootlist, decimal_point_index
As for arbitrary big numbers you could have a look at The GNU Multiple Precision Arithmetic Library (for C/C++).
For work? Use a library!
For fun? Good for you :)
Write a program to imitate what you would do with pencil and paper. Start with 1 digit, then 2 digits, then 3, ..., ...
Don't worry about Newton or anybody else. Just do it your way.
Here is a short version for calculating the square root of an integer a to digits of precision. It works by finding the integer square root of a after multiplying by 10 raised to the 2 x digits.
def sqroot(a, digits):
a = a * (10**(2*digits))
x_prev = 0
x_next = 1 * (10**digits)
while x_prev != x_next:
x_prev = x_next
x_next = (x_prev + (a // x_prev)) >> 1
return x_next
Just a few caveats.
You'll need to convert the result to a string and add the decimal point at the correct location (if you want the decimal point printed).
Converting a very large integer to a string isn't very fast.
Dividing very large integers isn't very fast (in Python) either.
Depending on the performance of your system, it may take an hour or longer to calculate the square root of 2 to 3 million decimal places.
I haven't proven the loop will always terminate. It may oscillate between two values differing in the last digit. Or it may not.
The nicest way is probably using the continued fraction expansion [1; 2, 2, ...] the square root of two.
def root_two_cf_expansion():
yield 1
while True:
yield 2
def z(a,b,c,d, contfrac):
for x in contfrac:
while a > 0 and b > 0 and c > 0 and d > 0:
t = a // c
t2 = b // d
if not t == t2:
break
yield t
a = (10 * (a - c*t))
b = (10 * (b - d*t))
# continue with same fraction, don't pull new x
a, b = x*a+b, a
c, d = x*c+d, c
for digit in rdigits(a, c):
yield digit
def rdigits(p, q):
while p > 0:
if p > q:
d = p // q
p = p - q * d
else:
d = (10 * p) // q
p = 10 * p - q * d
yield d
def decimal(contfrac):
return z(1,0,0,1,contfrac)
decimal((root_two_cf_expansion()) returns an iterator of all the decimal digits. t1 and t2 in the algorithm are minimum and maximum values of the next digit. When they are equal, we output that digit.
Note that this does not handle certain exceptional cases such as negative numbers in the continued fraction.
(This code is an adaptation of Haskell code for handling continued fractions that has been floating around.)
Well, the following is the code that I wrote. It generated a million digits after the decimal for the square root of 2 in about 60800 seconds for me, but my laptop was sleeping when it was running the program, it should be faster that. You can try to generate 3 million digits, but it might take a couple days to get it.
def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
if number[a]=='.':
decimal_point_locaiton=a
break
if a==len(number)-1:
number+='.'
decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
number='0'+number
decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
if number[a]!='0':
list.append(eval(number[a:a+2]))
else:
try:
list.append(eval(number[a+1]))
except IndexError:
pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
try:
c=c*100+list[a+1]
except IndexError:
c=c*100
while c!=0:
x=0
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
c=c*100
if len(ans)-decimal_point_ans>=digits_after_decimal:
break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total
Python already supports big integers out of the box, and if that's the only thing holding you back in C/C++ you can always write a quick container class yourself.
The only problem you've mentioned is a lack of big integers. If you don't want to use a library for that, then are you looking for help writing such a class?
Here's a more efficient integer square root function (in Python 3.x) that should terminate in all cases. It starts with a number much closer to the square root, so it takes fewer steps. Note that int.bit_length requires Python 3.1+. Error checking left out for brevity.
def isqrt(n):
x = (n >> n.bit_length() // 2) + 1
result = (x + n // x) // 2
while abs(result - x) > 1:
x = result
result = (x + n // x) // 2
while result * result > n:
result -= 1
return result
Related
I was bored at work and was playing with some math and python coding, when I noticed the following:
Recursively (or if using a for loop) you simply add integers together to get a given Fibonacci number. However there is also a direct equation for calculating Fibonacci numbers, and for large n this equation will give answers that are, frankly, quite wrong with respect to the recursively calculated Fibonacci number.
I imagine this is due to rounding and floating point arithmetic ( sqrt(5) is irrational after all), and if so can anyone point me into a direction on how I could modify the fibo_calc_direct function to return a more accurate result?
Thanks!
def fib_calc_recur(n, ii = 0, jj = 1):
#n is the index of the nth fibonacci number, F_n, where F_0 = 0, F_1 = 1, ...
if n == 0: #use recursion
return ii
if n == 1:
return jj
else:
return(fib_calc_recur(n -1, jj, ii + jj))
def fib_calc_direct(n):
a = (1 + np.sqrt(5))/2
b = (1 - np.sqrt(5))/2
f = (1/np.sqrt(5)) * (a**n - b**n)
return(f)
You could make use of Decimal numbers, and set its precision depending on the magninute of n
Not your question, but I'd use an iterative version of the addition method. Here is a script that makes both calculations (naive addition, direct with Decimal) for values of n up to 4000:
def fib_calc_iter(n):
a, b = 0, 1
if n < 2:
return n
for _ in range(1, n):
a, b = b, a + b
return b
from decimal import Decimal, getcontext
def fib_calc_decimal(n):
getcontext().prec = n // 4 + 3 # Choose a precision good enough for this n
sqrt5 = Decimal(5).sqrt()
da = (1 + sqrt5) / 2
db = (1 - sqrt5) / 2
f = (da**n - db**n) / sqrt5
return int(f + Decimal(0.5)) # Round to nearest int
# Test it...
for n in range(1, 4000):
x = fib_calc_iter(n)
y = fib_calc_decimal(n)
if x != y:
print(f"Difference found for n={n}.\nNaive method={x}.\nDecimal method={y}")
break
else:
print("No differences found")
How would I manage to perform math.ceil such that a number is assigned to the next highest power of 10?
# 0.04 -> 0.1
# 0.7 -> 1
# 1.1 -> 10
# 90 -> 100
# ...
My current solution is a dictionary that checks the range of the input number, but it's hardcoded and I would prefer a one-liner solution. Maybe I am missing a simple mathematical trick or a corresponding numpy function here?
You can use math.ceil with math.log10 to do this:
>>> 10 ** math.ceil(math.log10(0.04))
0.1
>>> 10 ** math.ceil(math.log10(0.7))
1
>>> 10 ** math.ceil(math.log10(1.1))
10
>>> 10 ** math.ceil(math.log10(90))
100
log10(n) gives you the solution x that satisfies 10 ** x == n, so if you round up x it gives you the exponent for the next highest power of 10.
Note that for a value n where x is already an integer, the "next highest power of 10" will be n:
>>> 10 ** math.ceil(math.log10(0.1))
0.1
>>> 10 ** math.ceil(math.log10(1))
1
>>> 10 ** math.ceil(math.log10(10))
10
Your problem is under-specified, you need to step back and ask some questions.
What type(s) are your inputs?
What type(s) do you want for your outputs?
For results less than 1, what exactly do you want to round to? Do you want actual powers of 10 or floating point approximations of powers of 10? You are aware that negative powers of 10 can't be expressed exactly in floating point right? Let's assume for now that you want floating point approximations of powers of 10.
If the input is exactly a power of 10 (or the closest floating point approximation of a power of 10), should the output be the same as the input? Or should it be the next power of 10 up? "10 -> 10" or "10 -> 100"? Let's assume the former for now.
Can your input values be any possible value of the types in question? or are they more constrained.
In another answer it was proposed to take the logarithm, then round up (ceiling function), then exponentiate.
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
Unfortunately this suffers from rounding errors. First of all n is converted from whatever data type it happens to have into a double precision floating point number, potentially introducing rounding errors, then the logarithm is calculated potentially introducing more rounding errors both in its internal calculations and in its result.
As such it did not take me long to find an example where it gave an incorrect result.
>>> import math
>>> from numpy import nextafter
>>> n = 1
>>> while (10 ** math.ceil(math.log10(nextafter(n,math.inf)))) > n:
... n *= 10
...
>>> n
10
>>> nextafter(n,math.inf)
10.000000000000002
>>> 10 ** math.ceil(math.log10(10.000000000000002))
10
It is also theoretically possible for it to fail in the other direction, though this seems to be much harder to provoke.
So for a robust solution for floats and ints we need to assume that the value of our logarithm is only approximate, and we must therefore test a couple of possibilities. Something along the lines of
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
I believe this code should give correct results for all arguments in a sensible real-world range of magnitudes. It will break for very small or very large numbers of non integer and non-floating point types because of issues converting them to floating point. Python special cases integer arguments to the log10 function in an attempt to prevent overflow, but still with a sufficiently massive integer it may be possible to force incorrect results due to rounding errors.
To test the two implementations I used the following test program.
n = -323 # 10**-324 == 0
while n < 1000:
v = 10 ** n
if v != nextpow10(v): print(str(v)+" bad")
try:
v = min(nextafter(v,math.inf),v+1)
except:
v += 1
if v > nextpow10(v): print(str(v)+" bad")
n += 1
This finds lots of failures in the naive implementation, but none in the improved implementation.
It seems you want rather the lowest next power of 10...
Here is a way using pure maths and no log, but recursion.
def ceiling10(x):
if (x > 10):
return ceiling10(x / 10) * 10
else:
if (x <= 1):
return ceiling10(10 * x) / 10
else:
return 10
for x in [1 / 1235, 0.5, 1, 3, 10, 125, 12345]:
print(x, ceiling10(x))
Check this out!
>>> i = 0.04123
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))
0.04123 0.1
>>> i = 0.712
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))
0.712 1
>>> i = 1.1
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))
1.1 10
>>> i = 90
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))
90 100
This code based on principle of ten's power in len(str(int(float_number))).
There are 4 cases:
int(i) > 1.
Float number - converted to int, thereafter string str() from it, will give us a string with length which is we are looking exactly. So, first part, for input i > 1.0 - it is ten 10 in power of this length.
& 3. Little branching: i > 1.0 and i > 0.1 <=> it is 10 and 1 respectively.
And last case, when i < 0.1: Here, ten shall be in negative power. To get first non zero element after comma, I've used such construction ("%.100f" % i).replace('.', '').index(k), where k run over [1:10] interval. Thereafter, take minimum of result list. And decrease by one, it is first zero, which shall be counted. Also, here standard python's index() may crash, if it will not find at least one of non-zero element from [1:10] interval, that is why in the end I must "filter" listing by occurrence: if str(j) in "%.100f" % i.
Additionally, to get deeper precise - %.100f may be taken differ.
I think the simplest way is:
import math
number = int(input('Enter a number: '))
next_pow_ten = round(10 ** math.ceil(math.log10(number)))
print(str(10) + ' power ' + str(round(math.log10(number))) + ' = '\
+ str(next_pow_ten))
I hope this help you.
a specific shortcut works for big-integers that are already coming in as string-format :
instead of having to first convert it to integer, or running it through the log()/ceiling() function, or perform any sort of modulo math, the next largest power-of-10 is simply :
10 ** length(big_int_str_var)
—- below : 1st one generates a string formatted power-of-10, the 2nd one is numeric
echo 23958699683561808518065081866850688652086158016508618152865101851111111111111 |
tee >( gpaste | gcat -n >&2; ) | gcat - |
python3 -c '\
import sys; [ print("1"+"0"*len(_.strip("\n"))) for _ in sys.stdin ]'
or '... [ print( 10 ** len(_.strip("\n"))) for _ in sys.stdin ]'
1 23958699683561808518065081866850688652086158016508618152865101851111111111111
1 100000000000000000000000000000000000000000000000000000000000000000000000000000
y = math.ceil(x)
z = y + (10 - (y % 10))
Something like this maybe? It's just off the top of my head but it worked when I tried a few numbers in terminal.
Examples,
1.Input=4
Output=111
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
------------------------
sum = 111(output)
1.Input=5
Output=237
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
5 = 1³ + 5³(divisors of 5)
-----------------------------
sum = 237 (output)
x=int(raw_input().strip())
tot=0
for i in range(1,x+1):
for j in range(1,i+1):
if(i%j==0):
tot+=j**3
print tot
Using this code I can find the answer for small number less than one million.
But I want to find the answer for very large numbers. Is there any algorithm
for how to solve it easily for large numbers?
Offhand I don't see a slick way to make this truly efficient, but it's easy to make it a whole lot faster. If you view your examples as matrices, you're summing them a row at a time. This requires, for each i, finding all the divisors of i and summing their cubes. In all, this requires a number of operations proportional to x**2.
You can easily cut that to a number of operations proportional to x, by summing the matrix by columns instead. Given an integer j, how many integers in 1..x are divisible by j? That's easy: there are x//j multiples of j in the range, so divisor j contributes j**3 * (x // j) to the grand total.
def better(x):
return sum(j**3 * (x // j) for j in range(1, x+1))
That runs much faster, but still takes time proportional to x.
There are lower-level tricks you can play to speed that in turn by constant factors, but they still take O(x) time overall. For example, note that x // j == 1 for all j such that x // 2 < j <= x. So about half the terms in the sum can be skipped, replaced by closed-form expressions for a sum of consecutive cubes:
def sum3(x):
"""Return sum(i**3 for i in range(1, x+1))"""
return (x * (x+1) // 2)**2
def better2(x):
result = sum(j**3 * (x // j) for j in range(1, x//2 + 1))
result += sum3(x) - sum3(x//2)
return result
better2() is about twice as fast as better(), but to get faster than O(x) would require deeper insight.
Quicker
Thinking about this in spare moments, I still don't have a truly clever idea. But the last idea I gave can be carried to a logical conclusion: don't just group together divisors with only one multiple in range, but also those with two multiples in range, and three, and four, and ... That leads to better3() below, which does a number of operations roughly proportional to the square root of x:
def better3(x):
result = 0
for i in range(1, x+1):
q1 = x // i
# value i has q1 multiples in range
result += i**3 * q1
# which values have i multiples?
q2 = x // (i+1) + 1
assert x // q1 == i == x // q2
if i < q2:
result += i * (sum3(q1) - sum3(q2 - 1))
if i+1 >= q2: # this becomes true when i reaches roughly sqrt(x)
break
return result
Of course O(sqrt(x)) is an enormous improvement over the original O(x**2), but for very large arguments it's still impractical. For example better3(10**6) appears to complete instantly, but better3(10**12) takes a few seconds, and better3(10**16) is time for a coffee break ;-)
Note: I'm using Python 3. If you're using Python 2, use xrange() instead of range().
One more
better4() has the same O(sqrt(x)) time behavior as better3(), but does the summations in a different order that allows for simpler code and fewer calls to sum3(). For "large" arguments, it's about 50% faster than better3() on my box.
def better4(x):
result = 0
for i in range(1, x+1):
d = x // i
if d >= i:
# d is the largest divisor that appears `i` times, and
# all divisors less than `d` also appear at least that
# often. Account for one occurence of each.
result += sum3(d)
else:
i -= 1
lastd = x // i
# We already accounted for i occurrences of all divisors
# < lastd, and all occurrences of divisors >= lastd.
# Account for the rest.
result += sum(j**3 * (x // j - i)
for j in range(1, lastd))
break
return result
It may be possible to do better by extending the algorithm in "A Successive Approximation Algorithm for Computing the Divisor Summatory Function". That takes O(cube_root(x)) time for the possibly simpler problem of summing the number of divisors. But it's much more involved, and I don't care enough about this problem to pursue it myself ;-)
Subtlety
There's a subtlety in the math that's easy to miss, so I'll spell it out, but only as it pertains to better4().
After d = x // i, the comment claims that d is the largest divisor that appears i times. But is that true? The actual number of times d appears is x // d, which we did not compute. How do we know that x // d in fact equals i?
That's the purpose of the if d >= i: guarding that comment. After d = x // i we know that
x == d*i + r
for some integer r satisfying 0 <= r < i. That's essentially what floor division means. But since d >= i is also known (that's what the if test ensures), it must also be the case that 0 <= r < d. And that's how we know x // d is i.
This can break down when d >= i is not true, which is why a different method needs to be used then. For example, if x == 500 and i == 51, d (x // i) is 9, but it's certainly not the case that 9 is the largest divisor that appears 51 times. In fact, 9 appears 500 // 9 == 55 times. While for positive real numbers
d == x/i
if and only if
i == x/d
that's not always so for floor division. But, as above, the first does imply the second if we also know that d >= i.
Just for Fun
better5() rewrites better4() for about another 10% speed gain. The real pedagogical point is to show that it's easy to compute all the loop limits in advance. Part of the point of the odd code structure above is that it magically returns 0 for a 0 input without needing to test for that. better5() gives up on that:
def isqrt(n):
"Return floor(sqrt(n)) for int n > 0."
g = 1 << ((n.bit_length() + 1) >> 1)
d = n // g
while d < g:
g = (d + g) >> 1
d = n // g
return g
def better5(x):
assert x > 0
u = isqrt(x)
v = x // u
return (sum(map(sum3, (x // d for d in range(1, u+1)))) +
sum(x // i * i**3 for i in range(1, v)) -
u * sum3(v-1))
def sum_divisors(n):
sum = 0
i = 0
for i in range (1, n) :
if n % i == 0 and n != 0 :
sum = sum + i
# Return the sum of all divisors of n, not including n
return sum
print(sum_divisors(0))
# 0
print(sum_divisors(3)) # Should sum of 1
# 1
print(sum_divisors(36)) # Should sum of 1+2+3+4+6+9+12+18
# 55
print(sum_divisors(102)) # Should be sum of 2+3+6+17+34+51
# 114
I was curious if any of you could come up with a more streamline version of code to calculate Brown numbers. as of the moment, this code can do ~650! before it moves to a crawl. Brown Numbers are calculated thought the equation n! + 1 = m**(2) Where M is an integer
brownNum = 8
import math
def squareNum(n):
x = n // 2
seen = set([x])
while x * x != n:
x = (x + (n // x)) // 2
if x in seen: return False
seen.add(x)
return True
while True:
for i in range(math.factorial(brownNum)+1,math.factorial(brownNum)+2):
if squareNum(i) is True:
print("pass")
print(brownNum)
print(math.factorial(brownNum)+1)
break
else:
print(brownNum)
print(math.factorial(brownNum)+1)
brownNum = brownNum + 1
continue
break
print(input(" "))
Sorry, I don't understand the logic behind your code.
I don't understand why you calculate math.factorial(brownNum) 4 times with the same value of brownNum each time through the while True loop. And in the for loop:
for i in range(math.factorial(brownNum)+1,math.factorial(brownNum)+2):
i will only take on the value of math.factorial(brownNum)+1
Anyway, here's my Python 3 code for a brute force search of Brown numbers. It quickly finds the only 3 known pairs, and then proceeds to test all the other numbers under 1000 in around 1.8 seconds on this 2GHz 32 bit machine. After that point you can see it slowing down (it hits 2000 around the 20 second mark) but it will chug along happily until the factorials get too large for your machine to hold.
I print progress information to stderr so that it can be separated from the Brown_number pair output. Also, stderr doesn't require flushing when you don't print a newline, unlike stdout (at least, it doesn't on Linux).
import sys
# Calculate the integer square root of `m` using Newton's method.
# Returns r: r**2 <= m < (r+1)**2
def int_sqrt(m):
if m <= 0:
return 0
n = m << 2
r = n >> (n.bit_length() // 2)
while True:
d = (n // r - r) >> 1
r += d
if -1 <= d <= 1:
break
return r >> 1
# Search for Browns numbers
fac = i = 1
while True:
if i % 100 == 0:
print('\r', i, file=sys.stderr, end='')
fac *= i
n = fac + 1
r = int_sqrt(n)
if r*r == n:
print('\nFound', i, r)
i += 1
You might want to:
pre calculate your square numbers, instead of testing for them on the fly
pre calculate your factorial for each loop iteration num_fac = math.factorial(brownNum) instead of multiple calls
implement your own, memoized, factorial
that should let you run to the hard limits of your machine
one optimization i would make would be to implement a 'wrapper' function around math.factorial that caches previous values of factorial so that as your brownNum increases, factorial doesn't have as much work to do. this is known as 'memoization' in computer science.
edit: found another SO answer with similar intention: Python: Is math.factorial memoized?
You should also initialize the square root more closely to the root.
e = int(math.log(n,4))
x = n//2**e
Because of 4**e <= n <= 4**(e+1) the square root will be between x/2 and x which should yield quadratic convergence of the Heron formula from the first iteration on.
How does one convert a base-10 floating point number in Python to a base-N floating point number?
Specifically in my case, I would like to convert numbers to base 3 (obtain the representation of floating point numbers in base 3), for calculations with the Cantor set.
After a bit of fiddling, here's what I came up with. I present it to you humbly, keeping in mind Ignacio's warning. Please let me know if you find any flaws. Among other things, I have no reason to believe that the precision argument provides anything more than a vague assurance that the first precision digits are pretty close to correct.
def base3int(x):
x = int(x)
exponents = range(int(math.log(x, 3)), -1, -1)
for e in exponents:
d = int(x // (3 ** e))
x -= d * (3 ** e)
yield d
def base3fraction(x, precision=1000):
x = x - int(x)
exponents = range(-1, (-precision - 1) * 2, -1)
for e in exponents:
d = int(x // (3 ** e))
x -= d * (3 ** e)
yield d
if x == 0: break
These are iterators returning ints. Let me know if you need string conversion; but I imagine you can handle that.
EDIT: Actually looking at this some more, it seems like a if x == 0: break line after the yield in base3fraction gives you pretty much arbitrary precision. I went ahead and added that. Still, I'm leaving in the precision argument; it makes sense to be able to limit that quantity.
Also, if you want to convert back to decimal fractions, this is what I used to test the above.
sum(d * (3 ** (-i - 1)) for i, d in enumerate(base3fraction(x)))
Update
For some reason I've felt inspired by this problem. Here's a much more generalized solution. This returns two generators that generate sequences of integers representing the integral and fractional part of a given number in an arbitrary base. Note that this only returns two generators to distinguish between the parts of the number; the algorithm for generating digits is the same in both cases.
def convert_base(x, base=3, precision=None):
length_of_int = int(math.log(x, base))
iexps = range(length_of_int, -1, -1)
if precision == None: fexps = itertools.count(-1, -1)
else: fexps = range(-1, -int(precision + 1), -1)
def cbgen(x, base, exponents):
for e in exponents:
d = int(x // (base ** e))
x -= d * (base ** e)
yield d
if x == 0 and e < 0: break
return cbgen(int(x), base, iexps), cbgen(x - int(x), base, fexps)
Although 8 years have passed, I think it is worthwhile to mention a more compact solution.
def baseConversion( x=1, base=3, decimals=2 ):
import math
n_digits = math.floor(-math.log(x, base))#-no. of digits in front of decimal point
x_newBase = 0#initialize
for i in range( n_digits, decimals+1 ):
x_newBase = x_newBase + int(x*base**i) % base * 10**(-i)
return x_newBase
For example calling the function to convert the number 5+1/9+1/27
def baseConversion( x=5+1/9+1/27, base=3, decimals=2 )
12.01
def baseConversion( x=5+1/9+1/27, base=3, decimals=3 )
12.011
You may try this solution to convert a float string to a given base.
def eval_strint(s, base=2):
assert type(s) is str
assert 2 <= base <= 36
###
### YOUR CODE HERE
###
return int(s,base)
def is_valid_strfrac(s, base=2):
return all([is_valid_strdigit(c, base) for c in s if c != '.']) \
and (len([c for c in s if c == '.']) <= 1)
def eval_strfrac(s, base=2):
assert is_valid_strfrac(s, base), "'{}' contains invalid digits for a base-{} number.".format(s, base)
stg = s.split(".")
float_point=0.0
if len(stg) > 1:
float_point = (eval_strint(stg[1],base) * (base**(-len(stg[1]))))
stg_float = eval_strint(stg[0],base) + float_point
return stg_float