Search code examples
pythoncommon-lispprecisionclispcode-translation

Running Python functions in CLISP


Are there any CLISP sources available? I could only find references to Stack.

I'm trying to run a python definition in CLISP - any suggestions on how I go about doing this? I'm fairly familiar in writing definitions in CLISP, but not in python... for starters I'm looking to rewrite this from python:

def f(x):
if x <= 1/2:
    return 2 * x
if x > 1/2:
    return 2*x - 1

Just to see how CLISP deals with computing fractions as a comparison I was going to run this, which I took from an online computational algebra course:

x = 1/10
for i in range(80):
    print(x)
    x = f(x)

Grateful for any suggestions...

Cheers.


Solution

  • So I don't really understand what you are trying to achieve, but let's try to run the Python example first. It is badly formatted currently (maybe there was a copy-paste problem), so here it is with proper indentation:

    def f(x):
        if (x <= 1/2):
            return 2 * x
        else:
            return (2 * x) - 1
    
    x = 1/10
    for i in range(80):
        print(x)
        x = f(x)
    

    In Python 2 this prints only zeroes, because you are not working with rational numbers, but just doing an integer division that truncates to zero (followed by multiplications by 2). In Python 3 the result would be a series of floats which converge towards 1.0, because floats are approximate (thanks @ex nihilo).

    CLISP is one specific implementation of the Common Lisp standard, among other ones (in no particular order Lispworks, ECL, SBCL, Allegro CL, Clozure Common Lisp, ABCL, CLASP, ...). Typically Common Lisp is abbreviated CL, or sometimes just Lisp (this is a somewhat controversial opinion), for the reason that other branches of the family decided to follow quite different philosphies and were named differently (Scheme, Clojure, or even Julia). They all belong however to the "Lisp family" of languages.

    If by CLISP you mean Common Lisp then an idiomatic way to code this would be:

    (defun f (x)
      (if (<= x 1/2)
          (* 2 x)
          (1- (* 2 x))))
    
    (loop
       for i below 80
       for x = 1/10 then (f x)
       collect x)
    

    This evaluates to(*):

    (1/10 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 
          1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 
          1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5
          1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5
          1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5 3/5 1/5 2/5 4/5)
    

    So if you want something equivalent in Python, you need to use fractions:

    from fractions import Fraction
    
    def f(x):
        if (x <= Fraction(1, 2)):
            return 2 * x
        else:
            return (2 * x) - 1
    
    x = Fraction(1,10)
    r = list()
    for i in range(80):
        r.append(x)
        x = f(x)
    

    The resulting list is:

    [Fraction(1, 10), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5), Fraction(3, 5), Fraction(1, 5), Fraction(2, 5), Fraction(4, 5)]
    

    (*) but

    (loop
       for i below 80
       for x = 0.1 then (f x)
       collect x)
    

    evaluates to

    (0.1 0.2 0.4 0.8 0.6 0.20000005 0.4000001 0.8000002 0.6000004 0.20000076
     0.40000153 0.80000305 0.6000061 0.2000122 0.4000244 0.8000488 0.60009766
     0.20019531 0.40039063 0.80078125 0.6015625 0.203125 0.40625 0.8125 0.625 0.25
     0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)
    

    and converting this back to rationals reveals it to be

    (13421773/134217728 13421773/67108864 13421773/33554432 13421773/16777216
     5033165/8388608 838861/4194304 838861/2097152 838861/1048576 314573/524288
     52429/262144 52429/131072 52429/65536 19661/32768 3277/16384 3277/8192 
     3277/4096 1229/2048 205/1024 205/512 205/256 77/128 13/64 13/32 13/16 5/8 
     1/4 1/2 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 
     1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 
     1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1 1/1)
    

    Indeed if we use 13421773/134217728 as the starting point in the loop, the resulting sequence is exactly the same.