Konzolni interaktivni kalkulator

Dobio sam zadatak od žene da sračunam površinu zidova i plafona za krečenje te sam napravio prigodni konzolni interaktivni kalkulator u python3.10 koji omogućava dodeljivanje izraza promenljivama i kasnije korišćenje tih promenljivih u daljim izračunavanjima. Ovaj program omogućava:

Unos izraza u obliku ime=izraz (npr. prozor=1.4*1.2).

Korišćenje prethodno definisanih promenljivih u novim izrazima (npr. otvori=prozor1+vrata1+vrata2+prozor3)

Prikaz svih promenljivih sa komandnom prikazi.

variables = {}

def evaluate_expression(expression):
    try:
        result = eval(expression, {"__builtins__": {}}, variables)
        return result
    except Exception as e:
        print(f"Greška u izrazu: {e}")
        return None

def main():
    print("Unesite izraze u formatu promenljiva=izraz (npr. prozor=1.4*1.2).")
    print("Za prikaz svih promenljivih unesite 'prikazi'. Za izlaz unesite 'izlaz'.")
    
    while True:
        unos = input(">> ").strip()
        
        if unos.lower() == "izlaz":
            break
        elif unos.lower() == "prikazi":
            for key, value in variables.items():
                print(f"{key} = {value}")
        elif "=" in unos:
            ime, izraz = map(str.strip, unos.split("=", 1))
            vrednost = evaluate_expression(izraz)
            if vrednost is not None:
                variables[ime] = vrednost
        else:
            print("Neispravan unos. Koristite 'ime=izraz' ili komande 'prikazi' i 'izlaz'.")
    
if __name__ == "__main__":
    main()

Sledi primer proračuna dnevne sobe, trpezarije i kuhinje:

Funkcija evaluate_expression(expression) ima sledeće funkcionalnosti:

  1. Evaluacija izraza
    • Koristi eval() za izračunavanje izraza.
    • Zabranjuje pristup ugrađenim funkcijama Python-a ({"__builtins__": {}}), čime se smanjuje rizik od nebezbednog izvršavanja koda.
    • Omogućava korišćenje promenljivih koje su prethodno definisane u variables.
  2. Rukovanje greškama
    • Ako dođe do greške prilikom evaluacije izraza (npr. nepostojeća promenljiva, sintaksna greška), ispisuje poruku o grešci i vraća None.
  3. Vraćanje rezultata
    • Ako je evaluacija uspešna, vraća izračunatu vrednost izraza.

U suštini, funkcija omogućava računanje izraza koji koriste brojeve i prethodno definisane promenljive, ali ne dozvoljava pozivanje ugrađenih funkcija Python-a radi sigurnosti.

Funkcija eval() u Pythonu omogućava evaluaciju izraza koji su zadati kao string. Njene mogućnosti su široke, ali su u našem kodu ograničene radi sigurnosti. Evo šta eval() može da izračuna:

1. Aritmetičke operacije

  • Sabiranje, oduzimanje, množenje, deljenje: eval("5 + 3 * 2") # 11 eval("10 / 2") # 5.0 eval("2 ** 3") # 8 (stepenovanje) eval("10 % 3") # 1 (modulo)

2. Korišćenje promenljivih

  • Može koristiti već definisane promenljive: variables = {"a": 10, "b": 5} eval("a + b", {"__builtins__": {}}, variables) # 15

3. Grupisanje i prioritet operacija

  • Može obrađivati izraze sa zagradama: eval("(2 + 3) * 4") # 20

4. Rad sa realnim brojevima

  • Podržava decimalne brojeve: eval("3.5 * 2.1") # 7.35

5. Negacije i apsolutne vrednosti

  • Može obraditi negativne brojeve: eval("-5 + 2") # -3

Šta eval() ne može u našem kodu?

Pošto koristimo {"__builtins__": {}}, eval() ne može:

  1. Pozivati bilo koju ugrađenu funkciju (print(), open(), exec(), os.system(), itd.).
  2. Pristupati fajlovima ili sistemskim komandama.
  3. Izvršavati složenije Python izraze poput petlji (for, while) ili definicija (def, class).

Ako želiš da podržiš i matematičke funkcije (sqrt, sin, cos, itd.), možemo dodati podršku za math modul na bezbedan način.

import math

variables = {}

def evaluate_expression(expression):
    try:
        allowed_functions = {name: getattr(math, name) for name in dir(math) if callable(getattr(math, name))}
        result = eval(expression, {"__builtins__": {}}, {**variables, **allowed_functions})
        return result
    except Exception as e:
        print(f"Greška u izrazu: {e}")
        return None

def main():
    print("Unesite izraze u formatu promenljiva=izraz (npr. prozor=1.4*1.2).")
    print("Možete koristiti matematičke funkcije iz 'math' modula (npr. sqrt, sin, cos).")
    print("Za prikaz svih promenljivih unesite 'prikazi'. Za izlaz unesite 'izlaz'.")
    
    while True:
        unos = input(">> ").strip()
        
        if unos.lower() == "izlaz":
            break
        elif unos.lower() == "prikazi":
            for key, value in variables.items():
                print(f"{key} = {value}")
        elif "=" in unos:
            ime, izraz = map(str.strip, unos.split("=", 1))
            vrednost = evaluate_expression(izraz)
            if vrednost is not None:
                variables[ime] = vrednost
        else:
            print("Neispravan unos. Koristite 'ime=izraz' ili komande 'prikazi' i 'izlaz'.")
    
if __name__ == "__main__":
    main()

Proširio sam funkcionalnost tako da sada možeš koristiti matematičke funkcije iz math modula, kao što su sqrt, sin, cos, log, itd. Na primer:

>> x = sqrt(25)
>> y = sin(3.14)
>> prikazi
x = 5.0
y = 0.0015926529164868282

Evo svih funkcija iz math modula koje sada možeš koristiti u programu, uz primere:

1. Trigonometrijske funkcije

math.sin(3.14)      # Sinus ugla (radijani)
math.cos(3.14)      # Kosinus ugla (radijani)
math.tan(3.14)      # Tangens ugla (radijani)
math.asin(0.5)      # Arkus sinus (vraća radijane)
math.acos(0.5)      # Arkus kosinus
math.atan(1)        # Arkus tangens
math.atan2(1, 1)    # Arkus tangens sa dve vrednosti (y, x)
math.sinh(1)        # Hiperbolički sinus
math.cosh(1)        # Hiperbolički kosinus
math.tanh(1)        # Hiperbolički tangens
math.asinh(1)       # Inverzni hiperbolički sinus
math.acosh(2)       # Inverzni hiperbolički kosinus
math.atanh(0.5)     # Inverzni hiperbolički tangens

2. Eksponencijalne i logaritamske funkcije

math.exp(2)         # e^2
math.exp2(3)        # 2^3
math.expm1(1)       # e^x - 1, preciznije za male vrednosti x
math.log(100)       # Logaritam baze e (ln)
math.log(100, 10)   # Logaritam baze 10
math.log10(100)     # Logaritam baze 10
math.log2(8)        # Logaritam baze 2
math.log1p(0.5)     # ln(1 + x), precizno za male x

3. Koreni i stepeni

math.sqrt(25)       # Kvadratni koren
math.cbrt(27)       # Kubni koren
math.pow(2, 3)      # 2^3

4. Aritmetičke funkcije

math.fabs(-10.5)    # Apsolutna vrednost
math.ceil(4.3)      # Zaokruživanje na više (5)
math.floor(4.8)     # Zaokruživanje na niže (4)
math.trunc(4.8)     # Odbacuje decimalni deo (4)
math.modf(5.75)     # Razdvaja decimalni i celobrojni deo (0.75, 5.0)
math.remainder(10, 3)  # Matematički ostatak pri deljenju
math.fmod(10, 3)    # Modulo (ostatak pri deljenju)

5. Kombinatorne funkcije

math.factorial(5)   # Faktorijel (5! = 5×4×3×2×1)
math.comb(5, 2)     # Kombinacije: koliko načina da izaberemo 2 od 5
math.perm(5, 2)     # Permutacije: koliko načina da rasporedimo 2 od 5
math.prod([1, 2, 3, 4])  # Proizvod svih brojeva u listi

6. Brojevne funkcije

math.gcd(48, 18)    # Najveći zajednički delilac
math.lcm(12, 15)    # Najmanji zajednički sadržalac
math.isqrt(10)      # Celi broj kvadratnog korena (int)

7. Rad sa uglovima

math.radians(180)   # Pretvara stepeni u radijane (π)
math.degrees(math.pi)  # Pretvara radijane u stepene (180°)

8. Specijalne funkcije

math.gamma(5)       # Gama funkcija (faktorijel proširen za realne brojeve)
math.lgamma(5)      # Logaritamska gama funkcija
math.erf(1)         # Greška funkcija
math.erfc(1)        # Komplementarna greška funkcija

Naredni Python program omogućava unos matematičkih izraza i dodelu rezultata promenljivama, uz podršku za funkcije iz math modula. Program čuva definisane promenljive i omogućava njihovo prikazivanje.

Poboljšanja:

  1. Podrška za korišćenje prethodno definisanih promenljivih
    • Trenutno već definisane promenljive mogu da se koriste, ali nema zaštite od unosa nepostojećih promenljivih.
    • Može se dodati provera i javljanje greške ako se pokuša koristiti nepoznata promenljiva.
  2. Bolja obrada grešaka
    • Trenutno se sve greške prikazuju generički (Greška u izrazu: ...).
    • Može se dodati specifična obrada za NameError, SyntaxError, ZeroDivisionError itd.
  3. Formatiranje ispisa vrednosti promenljivih
    • Može se podesiti broj decimala ili koristiti f"{value:.2f}" za bolji prikaz.
  4. Mogućnost izvoza promenljivih u fajl
    • Dodavanje komande sacuvaj ime_fajla koja bi sačuvala promenljive u .txt ili .json fajl.
  5. Učitavanje vrednosti iz fajla
    • Dodavanje komande ucitaj ime_fajla za vraćanje prethodno sačuvanih vrednosti.

import math
import json
import os

variables = {}

def evaluate_expression(expression):
    try:
        allowed_functions = {name: getattr(math, name) for name in dir(math) if callable(getattr(math, name))}
        result = eval(expression, {"__builtins__": {}}, {**variables, **allowed_functions})
        return round(result, 2)  # Formatiranje na 2 decimale
    except NameError as e:
        print(f"Greška: Nepoznata promenljiva ili funkcija. {e}")
    except ZeroDivisionError:
        print("Greška: Deljenje nulom nije dozvoljeno.")
    except SyntaxError:
        print("Greška: Sintaksna greška u izrazu.")
    except Exception as e:
        print(f"Greška u izrazu: {e}")
    return None

def save_variables(filename):
    try:
        with open(filename, "w") as f:
            json.dump(variables, f, indent=4)
        print(f"Promenljive sačuvane u {filename}.")
    except Exception as e:
        print(f"Greška pri čuvanju: {e}")

def load_variables(filename):
    global variables
    if os.path.exists(filename):
        try:
            with open(filename, "r") as f:
                variables = json.load(f)
            print(f"Promenljive učitane iz {filename}.")
        except Exception as e:
            print(f"Greška pri učitavanju: {e}")
    else:
        print("Fajl ne postoji.")

def main():
    print("Unesite izraze u formatu promenljiva=izraz (npr. prozor=1.4*1.2).")
    print("Možete koristiti matematičke funkcije iz 'math' modula (npr. sqrt, sin, cos).")
    print("Podržane funkcije:")
    print("  sqrt(x) - Kvadratni koren, npr. sqrt(16) = 4.0")
    print("  sin(x), cos(x), tan(x) - Trigonometrija u radijanima, npr. sin(3.14/2) = 1.0")
    print("  degrees(x) - Pretvara radijane u stepene, npr. degrees(3.14) = 180.0")
    print("  radians(x) - Pretvara stepene u radijane, npr. radians(180) = 3.14")
    print("  log(x) - Prirodni logaritam, npr. log(10) = 2.3")
    print("  log10(x) - Logaritam po bazi 10, npr. log10(100) = 2.0")
    print("  exp(x) - Eksponencijalna funkcija, npr. exp(2) = 7.39")
    print("  pow(x, y) - Stepenovanje, npr. pow(2, 3) = 8")
    print("  ceil(x) - Zaokružuje na sledeći ceo broj, npr. ceil(2.3) = 3")
    print("  floor(x) - Zaokružuje na manji ceo broj, npr. floor(2.7) = 2")
    print("Za prikaz svih promenljivih unesite 'prikazi'. Za izlaz unesite 'izlaz'.")
    print("Sačuvaj promenljive sa 'sacuvaj ime_fajla'. Učitaj sa 'ucitaj ime_fajla'.")
    
    while True:
        unos = input(">> ").strip()
        
        if unos.lower() == "izlaz":
            break
        elif unos.lower() == "prikazi":
            for key, value in variables.items():
                print(f"{key} = {value:.2f}")
        elif unos.startswith("sacuvaj"):
            _, filename = unos.split(maxsplit=1)
            save_variables(filename)
        elif unos.startswith("ucitaj"):
            _, filename = unos.split(maxsplit=1)
            load_variables(filename)
        elif "=" in unos:
            ime, izraz = map(str.strip, unos.split("=", 1))
            vrednost = evaluate_expression(izraz)
            if vrednost is not None:
                variables[ime] = vrednost
        else:
            print("Neispravan unos. Koristite 'ime=izraz' ili komande 'prikazi', 'sacuvaj', 'ucitaj' i 'izlaz'.")
    
if __name__ == "__main__":
    main()

Dodao sam sve opisane funkcionalnosti! Sada možeš:
✔ Koristiti ranije definisane promenljive bez greške.
✔ Dobiti preciznije poruke o greškama.
✔ Videti formatirane rezultate sa dve decimale.
✔ Sačuvati promenljive u fajl (sacuvaj ime_fajla).
✔ Učitati promenljive iz fajla (ucitaj ime_fajla).

Za proveru programa evo jednog kompleksnijeg matematičkog izraza koji uključuje eksponencijalne funkcije, trigonometriju i kvadratne korene:

Unesi ga u program ovako:

x = (sin(45) + cos(30) * sqrt(25) - exp(2.1)) / (log(10) + tan(60))

Proba programa u konzoli bi trebala da izgleda ovako:

A sve je počeolo od sračunavanja površine zidova i plafona za krečenje…

By Abel

Leave a Reply

Your email address will not be published. Required fields are marked *