Last active
September 25, 2018 04:04
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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