HP Forums
Code Analyzer for HP Calculators - Printable Version

+- HP Forums (https://www.hpmuseum.org/forum)
+-- Forum: Not HP Calculators (/forum-7.html)
+--- Forum: Not quite HP Calculators - but related (/forum-8.html)
+--- Thread: Code Analyzer for HP Calculators (/thread-18245.html)



Code Analyzer for HP Calculators - Thomas Klemm - 04-10-2022 07:25 PM

The Simulator

This Python program simulates an HP calculator:
Code:
X, Y, Z, T, L = [0] * 5
R = [0] * 10
SYMBOLIC = None


def trace(operation):
    def fmt(s):
        return str(s)
    
    def wrapper(*args):
        operation(*args)
        params = ' '.join(map(str, args))
        if SYMBOLIC:
            print((
              f"X: {fmt(X):<50s}    "
              f"Y: {fmt(Y):<50s}    "
              f"Z: {fmt(Z):<50s}    "
              f"T: {fmt(T):<50s}    "
              f"L: {fmt(L):<50s}    "
              f": {operation.__name__} {params}"
            ))
        else:
            print((
              f"X: {X:< 20.12e}    "
              f"Y: {Y:< 20.12e}    "
              f"Z: {Z:< 20.12e}    "
              f"T: {T:< 20.12e}    "
              f"L: {L:< 20.12e}    "
              f": {operation.__name__} {params}"
            ))
    return wrapper

# operations

@trace
def CHS(): # +/-
    global X, Y, Z, T, L
    X = -X

@trace
def ADD(): # +
    global X, Y, Z, T, L
    X, Y, Z, L = Y + X, Z, T, X

@trace
def SUB(): # -
    global X, Y, Z, T, L
    X, Y, Z, L = Y - X, Z, T, X

@trace
def MUL(): # *
    global X, Y, Z, T, L
    X, Y, Z, L = Y * X, Z, T, X

@trace
def DIV(): # /
    global X, Y, Z, T, L
    X, Y, Z, L = Y / X, Z, T, X

@trace
def MOD():
    global X, Y, Z, T, L
    X, Y, Z, L = Y % X, Z, T, X

@trace
def YTX(): # Y^X
    global X, Y, Z, T, L
    X, Y, Z, L = Y ** X, Z, T, X

# functions

@trace
def RECIPROCAL(): # 1/X
    global X, Y, Z, T, L
    X, L = 1 / X, X

@trace
def FACT(): # X!
    global X, Y, Z, T, L
    X, L = factorial(X), X

@trace
def XT2(): # X^2
    global X, Y, Z, T, L
    X, L = X ** 2, X

@trace
def SQRT():
    global X, Y, Z, T, L
    X, L = sqrt(X), X

@trace
def EXP(): # E^X
    global X, Y, Z, T, L
    X, L = exp(X), X

@trace
def LN():
    global X, Y, Z, T, L
    X, L = log(X), X

@trace
def TENTX(): # 10^X
    global X, Y, Z, T, L
    X, L = 10 ** X, X

@trace
def LOG():
    global X, Y, Z, T, L
    X, L = log(X) / log(10), X

# trigonometry    

@trace
def PI():
    global X, Y, Z, T, L
    X, Y, Z, T = pi, X, Y, Z

@trace
def SIN():
    global X, Y, Z, T, L
    X, L = sin(X), X

@trace
def ASIN():
    global X, Y, Z, T, L
    X, L = asin(X), X

@trace
def COS():
    global X, Y, Z, T, L
    X, L = cos(X), X

@trace
def ACOS():
    global X, Y, Z, T, L
    X, L = acos(X), X

@trace
def TAN():
    global X, Y, Z, T, L
    X, L = tan(X), X

@trace
def ATAN():
    global X, Y, Z, T, L
    X, L = atan(X), X

# hyperbolic

@trace
def SINH():
    global X, Y, Z, T, L
    X, L = sinh(X), X

@trace
def ASINH():
    global X, Y, Z, T, L
    X, L = asinh(X), X

@trace
def COSH():
    global X, Y, Z, T, L
    X, L = cosh(X), X

@trace
def ACOSH():
    global X, Y, Z, T, L
    X, L = acosh(X), X

@trace
def TANH():
    global X, Y, Z, T, L
    X, L = tanh(X), X

@trace
def ATANH():
    global X, Y, Z, T, L
    X, L = atanh(X), X

# stack

@trace
def number(n):
    global X, Y, Z, T, L
    X, Y, Z, T = n, X, Y, Z

@trace
def SWAP(): # X<>Y
    global X, Y, Z, T, L
    X, Y = Y, X

@trace
def DUP(): # ENTER
    global X, Y, Z, T, L
    Y, Z, T = X, Y, Z

@trace
def RUP(): # R^
    global X, Y, Z, T, L
    X, Y, Z, T = T, X, Y, Z

@trace
def RDN(): # Rv
    global X, Y, Z, T, L
    X, Y, Z, T = Y, Z, T, X

@trace
def LASTX():
    global X, Y, Z, T, L
    X, Y, Z, T = L, X, Y, Z

@trace
def CLST():
    global X, Y, Z, T, L
    X, Y, Z, T, L = [0] * 5

# register

@trace
def CLRG():
    global X, Y, Z, T, L
    R = [0] * 10

@trace
def STO(n):
    global X, Y, Z, T, L
    R[n] = X

@trace
def RCL(n):
    global X, Y, Z, T, L
    X, Y, Z, T = R[n], X, Y, Z

The stack and the use of registers is implemented.
Also the most common functions are provided.

Writing Programs

It is straight forward to write a program using these functions.

Area of a Circle

This program calculates the area of a circle based on the radius \(r\):

\(
A = \pi r^2
\)

Code:
def area(r):
    global X, Y, Z, T, L
    X = r

    XT2()       # X^2
    PI()        # PI
    MUL()       # *

Quadratic Equation

This program calculates the solution of the quadratic equation based on the coefficients \(a\), \(b\) and \(c\):

\(
a x^2 + b x + c = 0
\)

Code:
def quadratic_equation(a, b, c):
    global X, Y, Z, T, L
    X, Y, Z = c, b, a

    DUP()       # ENTER
    RUP()       # R^
    DIV()       # /
    RUP()       # R^
    LASTX()     # LASTX
    DIV()       # /
    number(-2)  # -2
    DIV()       # /
    DUP()       # ENTER
    DUP()       # ENTER
    XT2()       # X^2
    RUP()       # R^
    SUB()       # -
    SQRT()      # SQRT
    SUB()       # -
    SWAP()      # X<>Y
    LASTX()     # LASTX
    ADD()       # +

Numeric Evaluation

Import the math Library

If we want to analyze the numeric values we import the math library:
Code:
from math import (
    pi,
    sqrt,
    factorial,
    exp,
    log,
    sin,
    asin,
    cos,
    acos,
    tan,
    atan,
    sinh,
    asinh,
    cosh,
    acosh,
    tanh,
    atanh,
)

SYMBOLIC = False
CLST()

X:  0.000000000000e+00     Y:  0.000000000000e+00     Z:  0.000000000000e+00     T:  0.000000000000e+00     L:  0.000000000000e+00     : CLST 


Area of a Circle

Code:
r = 4

area(r)

X:  1.600000000000e+01     Y:  0.000000000000e+00     Z:  0.000000000000e+00     T:  0.000000000000e+00     L:  4.000000000000e+00     : XT2 
X:  3.141592653590e+00     Y:  1.600000000000e+01     Z:  0.000000000000e+00     T:  0.000000000000e+00     L:  4.000000000000e+00     : PI 
X:  5.026548245744e+01     Y:  0.000000000000e+00     Z:  0.000000000000e+00     T:  0.000000000000e+00     L:  3.141592653590e+00     : MUL 


Quadratic Equation

Code:
a, b, c = 1, -1, -1

quadratic_equation(a, b, c)

X: -1.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T:  1.000000000000e+00     L:  0.000000000000e+00     : DUP 
X:  1.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L:  0.000000000000e+00     : RUP 
X: -1.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L:  1.000000000000e+00     : DIV 
X: -1.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L:  1.000000000000e+00     : RUP 
X:  1.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L:  1.000000000000e+00     : LASTX 
X: -1.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L:  1.000000000000e+00     : DIV 
X: -2.000000000000e+00     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L:  1.000000000000e+00     : number -2
X:  5.000000000000e-01     Y: -1.000000000000e+00     Z: -1.000000000000e+00     T: -1.000000000000e+00     L: -2.000000000000e+00     : DIV 
X:  5.000000000000e-01     Y:  5.000000000000e-01     Z: -1.000000000000e+00     T: -1.000000000000e+00     L: -2.000000000000e+00     : DUP 
X:  5.000000000000e-01     Y:  5.000000000000e-01     Z:  5.000000000000e-01     T: -1.000000000000e+00     L: -2.000000000000e+00     : DUP 
X:  2.500000000000e-01     Y:  5.000000000000e-01     Z:  5.000000000000e-01     T: -1.000000000000e+00     L:  5.000000000000e-01     : XT2 
X: -1.000000000000e+00     Y:  2.500000000000e-01     Z:  5.000000000000e-01     T:  5.000000000000e-01     L:  5.000000000000e-01     : RUP 
X:  1.250000000000e+00     Y:  5.000000000000e-01     Z:  5.000000000000e-01     T:  5.000000000000e-01     L: -1.000000000000e+00     : SUB 
X:  1.118033988750e+00     Y:  5.000000000000e-01     Z:  5.000000000000e-01     T:  5.000000000000e-01     L:  1.250000000000e+00     : SQRT 
X: -6.180339887499e-01     Y:  5.000000000000e-01     Z:  5.000000000000e-01     T:  5.000000000000e-01     L:  1.118033988750e+00     : SUB 
X:  5.000000000000e-01     Y: -6.180339887499e-01     Z:  5.000000000000e-01     T:  5.000000000000e-01     L:  1.118033988750e+00     : SWAP 
X:  1.118033988750e+00     Y:  5.000000000000e-01     Z: -6.180339887499e-01     T:  5.000000000000e-01     L:  1.118033988750e+00     : LASTX 
X:  1.618033988750e+00     Y: -6.180339887499e-01     Z:  5.000000000000e-01     T:  5.000000000000e-01     L:  1.118033988750e+00     : ADD 


Symbolic Evaluation

Import the sympy Library

If we want to analyze the symbolic values we import the sympy library:
Code:
from sympy import (
    pi,
    sqrt,
    factorial,
    exp,
    log,
    sin,
    asin,
    cos,
    acos,
    tan,
    atan,
    sinh,
    asinh,
    cosh,
    acosh,
    tanh,
    atanh,
    symbols,
    expand,
    simplify,
    latex,
)

SYMBOLIC = True
CLST()

X: 0                                                     Y: 0                                                     Z: 0                                                     T: 0                                                     L: 0                                                     : CLST  


Area of a Circle

Code:
r = symbols("r")

area(r)

X: r**2                                                  Y: 0                                                     Z: 0                                                     T: 0                                                     L: r                                                     : XT2 
X: pi                                                    Y: r**2                                                  Z: 0                                                     T: 0                                                     L: r                                                     : PI 
X: pi*r**2                                               Y: 0                                                     Z: 0                                                     T: 0                                                     L: pi                                                    : MUL 


Quadratic Equation

Code:
a, b, c = symbols("a b c")

quadratic_equation(a, b, c)

X: c                                                     Y: c                                                     Z: b                                                     T: a                                                     L: 0                                                     : DUP 
X: a                                                     Y: c                                                     Z: c                                                     T: b                                                     L: 0                                                     : RUP 
X: c/a                                                   Y: c                                                     Z: b                                                     T: b                                                     L: a                                                     : DIV 
X: b                                                     Y: c/a                                                   Z: c                                                     T: b                                                     L: a                                                     : RUP 
X: a                                                     Y: b                                                     Z: c/a                                                   T: c                                                     L: a                                                     : LASTX 
X: b/a                                                   Y: c/a                                                   Z: c                                                     T: c                                                     L: a                                                     : DIV 
X: -2                                                    Y: b/a                                                   Z: c/a                                                   T: c                                                     L: a                                                     : number -2
X: -b/(2*a)                                              Y: c/a                                                   Z: c                                                     T: c                                                     L: -2                                                    : DIV 
X: -b/(2*a)                                              Y: -b/(2*a)                                              Z: c/a                                                   T: c                                                     L: -2                                                    : DUP 
X: -b/(2*a)                                              Y: -b/(2*a)                                              Z: -b/(2*a)                                              T: c/a                                                   L: -2                                                    : DUP 
X: b**2/(4*a**2)                                         Y: -b/(2*a)                                              Z: -b/(2*a)                                              T: c/a                                                   L: -b/(2*a)                                              : XT2 
X: c/a                                                   Y: b**2/(4*a**2)                                         Z: -b/(2*a)                                              T: -b/(2*a)                                              L: -b/(2*a)                                              : RUP 
X: -c/a + b**2/(4*a**2)                                  Y: -b/(2*a)                                              Z: -b/(2*a)                                              T: -b/(2*a)                                              L: c/a                                                   : SUB 
X: sqrt(-c/a + b**2/(4*a**2))                            Y: -b/(2*a)                                              Z: -b/(2*a)                                              T: -b/(2*a)                                              L: -c/a + b**2/(4*a**2)                                  : SQRT 
X: -sqrt(-c/a + b**2/(4*a**2)) - b/(2*a)                 Y: -b/(2*a)                                              Z: -b/(2*a)                                              T: -b/(2*a)                                              L: sqrt(-c/a + b**2/(4*a**2))                            : SUB 
X: -b/(2*a)                                              Y: -sqrt(-c/a + b**2/(4*a**2)) - b/(2*a)                 Z: -b/(2*a)                                              T: -b/(2*a)                                              L: sqrt(-c/a + b**2/(4*a**2))                            : SWAP 
X: sqrt(-c/a + b**2/(4*a**2))                            Y: -b/(2*a)                                              Z: -sqrt(-c/a + b**2/(4*a**2)) - b/(2*a)                 T: -b/(2*a)                                              L: sqrt(-c/a + b**2/(4*a**2))                            : LASTX 
X: sqrt(-c/a + b**2/(4*a**2)) - b/(2*a)                  Y: -sqrt(-c/a + b**2/(4*a**2)) - b/(2*a)                 Z: -b/(2*a)                                              T: -b/(2*a)                                              L: sqrt(-c/a + b**2/(4*a**2))                            : ADD 


Ad Hoc Calculations

We can also do some ad hoc calculations:
Code:
x = symbols("x")

CLST()
X = x
ATAN()
SIN()

X: 0                                                     Y: 0                                                     Z: 0                                                     T: 0                                                     L: 0                                                     : CLST 
X: atan(x)                                               Y: 0                                                     Z: 0                                                     T: 0                                                     L: x                                                     : ATAN 
X: x/sqrt(x**2 + 1)                                      Y: 0                                                     Z: 0                                                     T: 0                                                     L: atan(x)                                               : SIN 


LaTeX Support

These results can be transformed into LaTeX:
Code:
print(latex(X))

\frac{x}{\sqrt{x^{2} + 1}}

\(
\frac{x}{\sqrt{x^{2} + 1}}
\)

If we want all results printed in LaTeX we can modify the fmt function:
Code:
    def fmt(s):
        return latex(s)

Complex Numbers

I haven't tried this yet, but we could import the functions from the cmath library.
However, the formatting will likely require some adjustments.

Caveat
  • LBL and GTO are missing, but we can simulate that with the Python control structures
  • stack lift isn't handled, but that's not usually a problem in programs
  • probably something is still missing

Still, I hope this might be useful.


RE: Code Analyzer for HP Calculators - Namir - 04-11-2022 09:56 AM

Very nice work!! Your Python code is elegant.

Namir


RE: Code Analyzer for HP Calculators - Thomas Klemm - 04-11-2022 06:08 PM

(04-11-2022 09:56 AM)Namir Wrote:  Your Python code is elegant.

Well I must admit that I cobbled that together in a Jupyter notebook.
And that's probably the best environment to run it.

The state of the calculator is stored in these global variables, which I usually avoid.
So I had to declare them global in each of the functions.
But that along with the trace decorator makes them short and hopefully easy to understand.

(04-10-2022 07:25 PM)Thomas Klemm Wrote:  I haven't tried this yet, but we could import the functions from the cmath library.
However, the formatting will likely require some adjustments.

If we want to analyze complex values we import the cmath library:
Code:
from cmath import (
    pi,
    sqrt,
    exp,
    log,
    sin,
    asin,
    cos,
    acos,
    tan,
    atan,
    sinh,
    asinh,
    cosh,
    acosh,
    tanh,
    atanh,
)

SYMBOLIC = False
CLST()

The trace function needs minor adjustments:
Code:
            print((
              f"X: {X:< 30.6e}    "
              f"Y: {Y:< 30.6e}    "
              f"Z: {Z:< 30.6e}    "
              f"T: {T:< 30.6e}    "
              f"L: {L:< 30.6e}    "
              f": {operation.__name__} {params}"
            ))

And now we can also solve a quadratic equation with complex solutions:
Code:
a, b, c = 1, 1, 1

quadratic_equation(a, b, c)

X:  1.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  0.000000e+00                     : DUP 
X:  1.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  0.000000e+00                     : RUP 
X:  1.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  1.000000e+00                     : DIV 
X:  1.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  1.000000e+00                     : RUP 
X:  1.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  1.000000e+00                     : LASTX 
X:  1.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  1.000000e+00                     : DIV 
X: -2.000000e+00                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L:  1.000000e+00                     : number -2
X: -5.000000e-01                     Y:  1.000000e+00                     Z:  1.000000e+00                     T:  1.000000e+00                     L: -2.000000e+00                     : DIV 
X: -5.000000e-01                     Y: -5.000000e-01                     Z:  1.000000e+00                     T:  1.000000e+00                     L: -2.000000e+00                     : DUP 
X: -5.000000e-01                     Y: -5.000000e-01                     Z: -5.000000e-01                     T:  1.000000e+00                     L: -2.000000e+00                     : DUP 
X:  2.500000e-01                     Y: -5.000000e-01                     Z: -5.000000e-01                     T:  1.000000e+00                     L: -5.000000e-01                     : XT2 
X:  1.000000e+00                     Y:  2.500000e-01                     Z: -5.000000e-01                     T: -5.000000e-01                     L: -5.000000e-01                     : RUP 
X: -7.500000e-01                     Y: -5.000000e-01                     Z: -5.000000e-01                     T: -5.000000e-01                     L:  1.000000e+00                     : SUB 
X:  0.000000e+00+8.660254e-01j       Y: -5.000000e-01                     Z: -5.000000e-01                     T: -5.000000e-01                     L: -7.500000e-01                     : SQRT 
X: -5.000000e-01-8.660254e-01j       Y: -5.000000e-01                     Z: -5.000000e-01                     T: -5.000000e-01                     L:  0.000000e+00+8.660254e-01j       : SUB 
X: -5.000000e-01                     Y: -5.000000e-01-8.660254e-01j       Z: -5.000000e-01                     T: -5.000000e-01                     L:  0.000000e+00+8.660254e-01j       : SWAP 
X:  0.000000e+00+8.660254e-01j       Y: -5.000000e-01                     Z: -5.000000e-01-8.660254e-01j       T: -5.000000e-01                     L:  0.000000e+00+8.660254e-01j       : LASTX 
X: -5.000000e-01+8.660254e-01j       Y: -5.000000e-01-8.660254e-01j       Z: -5.000000e-01                     T: -5.000000e-01                     L:  0.000000e+00+8.660254e-01j       : ADD 



RE: Code Analyzer for HP Calculators - Sylvain Cote - 04-11-2022 10:44 PM

Interesting ...
I have run it inside PyCharm IDE from JetBrains.
Thank you Thomas!
Sylvain


RE: Code Analyzer for HP Calculators - Thomas Klemm - 04-12-2022 11:27 PM

Good to know it works for others too.
Thanks for checking that.

Meanwhile, I posted a simulator for the HP-80 CPU in this other thread.
Actually, I wrote that first and then thought to myself that it also fits for the analysis of programs from HP calculators.