Skip to content

Instantly share code, notes, and snippets.

@random-person-001
Last active September 25, 2018 04:04
Show Gist options
  • Save random-person-001/981906ba88a44be0e7cf3dc38dd744dd to your computer and use it in GitHub Desktop.
Save random-person-001/981906ba88a44be0e7cf3dc38dd744dd to your computer and use it in GitHub Desktop.
Calculate superroots of numbers to arbitrary precision with python. With a separate process, it can provide a fancy graph of how fast it's doing things.
# Python
# Written by me and a friend
# on 15 Sept 2018
#
# Written to run on Linux. For windows, change the system('clear') to the windows version (idk)
# Works way better in python2 than python3. I think that's something to do with the decimal library, which is weird.
# Requires matplotlib
#
from decimal import *
from os import system
import datetime
import numpy as np
from ctypes import c_int, c_float, c_long, c_double, c_char_p, c_char
from time import sleep, time
from multiprocessing import Value, Array, Process
# Fancy stuff for fun info
import matplotlib.pyplot as plt
start = datetime.datetime.now()
ctx = Context() # Decimal thingy
# For fun info:
def powtow(num, nth):
"""
A power tower function. This will return -1 if it overflowed
"""
if num == 0:
return 0
sofar = Decimal(num)
num = Decimal(num)
for k in range(1, nth):
# print("attempting ctx.power({}, {})".format(num, sofar))
try:
sofar = ctx.power(num, sofar)
except Overflow:
return -1
# print(type(sofar))
return sofar
def sr(num, nth, precision, prettyinfo=True):
"""
Calculate the `nth` superroot of a `num` to `precision` decimal places
Don't use rediculous numbers and expect correct results.
None of the inputs should be negative.
If you set prettyinfo to False, then it won't show a nice live updating
graph of ms of calculation for each digit, and nice terminal output
"""
title = "Calculating {}th superroot of {} to {} decimals of precision".format(
nth, num, precision)
if prettyinfo:
# a C Array of the timestamps (sec) it was at when it calcuated the digit in the `i`th
# place in the list. Type is c_int, length is precision+1
c_timelist = Array(c_long, int(precision + 2), lock=False)
c_ans = Array(c_char, precision+2, lock=False)
#c_ans = c_char_p("0.0")
p = Process(target=show, args=(c_timelist, c_ans, precision, title,))
p.start()
getcontext().prec = precision + 4 # give a few extra, just to be safe
ans = Decimal(0)
num = Decimal(num)
print(title)
if prettyinfo:
c_timelist[0] = int(1000*time())
while True:
temp = powtow(ans, nth)
if temp > num or temp == -1:
ans -= 1
break
elif temp == num:
break
ans += 1
if ans == -1: # haha whoops
ans = 0
print(ans)
if prettyinfo:
c_timelist[1] = int(1000*time())
for digitIndex in range(1, precision + 1):
for j in range(10):
temp = powtow(ans, nth)
if temp > num or temp == -1:
break
ans += Decimal(1 * 10 ** (-digitIndex))
ans -= Decimal(1 * 10 ** (-digitIndex))
if prettyinfo:
#c_ans = list(str(ans))
c_timelist[digitIndex + 1] = int(1000*time())
#print("important stuff: " + c_ans.value)
strans = str(ans)
decimalindex = strans.index(".")
strans = strans[:decimalindex + precision + 1]
print(("Calculated {}th superroot of {} to {} decimals of precision" +
"\n result was {}").format(nth, num, precision, strans))
return ans
def show(c_timelist, c_ans, precision, title):
"""
c_timelist : C_Array<floats> of seconds
precision does not change, so is a python object. Same with title.
c_ans is a c_string, of the python Decimal object earlier
Output fun info along the way.
This outputs nice info in the terminal, and keeps a live graph of dt for each digit going
"""
# a list of the times it took to calcuate the digit in the `i`th place in the
# list. It's python stuff, not C
dtlist = []
fig, ax = plt.subplots()
plt.show(block=False)
while True:
pytimelist = np.ndarray((len(c_timelist),), 'l', c_timelist, order='C')
dtlist = [] # reset every loop
strans = c_ans
#print("show read c_ans.value as " + str(c_ans[5]))
#print("\n")
#for c in range(precision):
# print(c_ans[c], end=',')
# #print(
for i in range(2, precision+1):
dt = pytimelist[i - 1] - pytimelist[i - 2]
if dt < 0:
dt = 0
dtlist.append(dt)
if len(dtlist) >= 2:
if dtlist[-1] == 0 and dtlist[-2] > 0:
pass
#decimalindex = strans.index(".")
#strans = strans[:decimalindex + (i - 1) + 1]
#system('clear')
#print("Precision: {} of {} decimal places - result = {}".format(i-1, precision, strans))
#print("Took {} ms to calculate latest digit".format(round(dtlist[-2])))
if len(dtlist) > 1:
x = range(len(dtlist))
y = dtlist
ax.clear()
ax.plot(x, y)
plt.xlabel("Digit #")
plt.ylabel("ms to calculate")
plt.title(title)
fig.canvas.draw()
sleep(.04)
if dtlist[-1] != 0:
plt.close()
print("All done!")
return
def testPretty():
sr(500, 70, 200, prettyinfo=True)
def testNotPretty():
sr(500, 70, 200, prettyinfo=False)
def timetest():
import timeit
pretty = timeit.timeit(stmt=testPretty, number=10)
npretty = timeit.timeit(stmt=testNotPretty, number=10)
print("Pretty time:\n" + str(pretty))
print("Non pretty time:\n" + str(npretty))
if __name__ == "__main__":
pass
#timetest()
#print(type(powtow(2, 3)))
# sr(2,3,10)
# sr(65536,4,10)
# sr(527807,12,400)
#sr(500,500,2000)
#print("\n"*5+"="*30+"\n"*3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment