#!/usr/bin/python3 # The MIT License (MIT) # # Copyright © 2020-2025 pacman64 # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # inca.pyw # # INteger-input CAlculator is a GUI app which live-evaluates the python # expression currently in its single-line input, re-running it as it changes # for each value in the integer range defined by 2 more expressions. from json import dumps import math from math import \ acos, acosh, asin, asinh, atan, atan2, atanh, ceil, comb, \ copysign, cos, cosh, degrees, dist, e, erf, erfc, exp, expm1, \ fabs, factorial, floor, fmod, frexp, fsum, gamma, gcd, hypot, inf, \ isclose, isfinite, isinf, isnan, isqrt, lcm, ldexp, lgamma, log, \ log10, log1p, log2, modf, nan, nextafter, perm, pi, pow, prod, \ radians, remainder, sin, sinh, sqrt, tan, tanh, tau, trunc, ulp try: from math import cbrt, exp2 except Exception: pass from random import \ betavariate, choice, choices, expovariate, gammavariate, gauss, \ getrandbits, getstate, lognormvariate, normalvariate, paretovariate, \ randbytes, randint, random, randrange, sample, seed, setstate, \ shuffle, triangular, uniform, vonmisesvariate, weibullvariate from statistics import \ bisect_left, bisect_right, fmean, \ geometric_mean, harmonic_mean, mean, median, \ median_grouped, median_high, median_low, mode, multimode, pstdev, \ pvariance, quantiles, stdev, variance try: from statistics import \ correlation, covariance, linear_regression, mul, reduce except Exception: pass from tkinter.ttk import Treeview from tkinter.messagebox import showerror from tkinter import Entry, Frame, Label, StringVar, Tk, END, LEFT # some convenience aliases to various funcs from the python stdlib geomean = geometric_mean harmean = harmonic_mean sd = stdev popsd = pstdev var = variance popvar = pvariance randbeta = betavariate randexp = expovariate randgamma = gammavariate randlognorm = lognormvariate randnorm = normalvariate randweibull = weibullvariate # some occasionally-useful values kb = 1024 mb = 1024 * kb gb = 1024 * mb tb = 1024 * gb pb = 1024 * tb mole = 602214076000000000000000 mol = mole # quick guide for the treeview-specific api # https://riptutorial.com/tkinter/example/31880/treeview--basic-example def update() -> None: 'Evaluates the current formula, then updates the bottom table.' # try to get the range of input values try: start = int(eval(fromnum.get())) stop = int(eval(tonum.get())) except Exception: return # clear the output for c in out.get_children(): out.delete(c) # update output rows j = 0 # the actual row-insertion index src = inp.get() for i, n in enumerate(range(start, stop + 1)): if i >= 1000: # avoid hanging the GUI, so quit after calculating 1000 rows break # visually-separate groups of 5 rows by adding an empty one if i > 0 and i % 5 == 0: out.insert('', j, text='') j += 1 # calculate formula-result for the current value try: x = n # allow x in formulas, as an alias for n y = eval(src) except Exception as e: val = [f'{n}', f'{e}'] out.insert('', j, text=f'{i + 1}', values=val) # make it obvious an error just occurred and return inp.config(bg='darkred', fg='white') out.heading('result', text='f(n)') return # insert row with the current result if isinstance(y, int) or isinstance(y, float): val = [f'{n}', f'{y:,.6f}'] else: val = [f'{n}', str(y)] out.insert('', j, text=f'{i + 1}', values=val) j += 1 out.heading('result', text=src) # reset style to indicate success inp.config(bg='white', fg='black') try: win = Tk() win.title('INteger-input CAlculator') win.bind('', lambda _: win.quit()) # top of window: formula and integer-range inputs top = Frame(win) Label(top, text='f(n) = ', font=30).grid(row=0, column=0, padx=0) inp = Entry(top, text=StringVar(value='n'), width=32, borderwidth=1) inp.select_range(0, END) inp.grid(row=0, column=1, padx=0, sticky='e') inp.bind('', lambda _: update()) inp.focus_set() Label(top, text='n = ', font=20).grid(row=0, column=2, padx=10) fromnum = Entry(top, text=StringVar(value=1), width=6, borderwidth=1) fromnum.grid(row=0, column=3, padx=2, sticky='e') fromnum.bind('', lambda _: update()) Label(top, text=' .. ', font=20).grid(row=0, column=4, padx=0) tonum = Entry(top, text=StringVar(value=40), width=6, borderwidth=1) tonum.grid(row=0, column=5, padx=2, sticky='e') tonum.bind('', lambda _: update()) top.pack(padx=1, pady=1, anchor='e') # bottom of window only has results table bottom = Frame(win) out = Treeview(bottom, column=['n', 'result'], height=48) out.heading('#0', text='#') out.column('#0', width=80) out.heading('n', text='n') out.column('n', width=80, anchor='e') out.heading('result', text='f(n)') out.column('result', width=360, anchor='e') out.pack() bottom.pack(side=LEFT, padx=1, pady=1) # show results and run gui update() win.mainloop() except Exception as e: showerror('Error', str(e)) win.quit()