4

I am a Common Lisp beginner, but not so in C++. There's a simple C++ program that I am trying to mirror in CL (see Pollard's Rho algorithm variant example in C++ ). The C++ program runs without errors. One requirement is that all the outputs from both the programs must match.

C++ version

int gcd(int a, int b) {
    int remainder;
    while (b != 0) {
        remainder = a % b;
        a = b;
        b = remainder;
    }
    return a;
}

int prime () {
    int n = 10403, x_fixed = 2, cycle_size = 2, x = 2, factor = 1;

    while (factor == 1) {
        for (int count=1;count <= cycle_size && factor <= 1;count++) {
            x = (x*x+1)%n;
            factor = gcd(x - x_fixed, n);
        }

        cycle_size *= 2;
        x_fixed = x;
    }
    cout << "\nThe factor is  " << factor;
return 0;
}

Common Lisp version

Here is what I've come up with. The debugging is giving me nightmares, yet I tried a lot many times and stepped through the entire code, still I have no idea where I have gone wrong :(

(defun prime () 
  (setq n 10403) 
  (setq x_fixed 2) 
  (setq cycle_size 2)
  (setq x 2) 
  (setq factor 1)
  (setq count 1) 
  (while_loop))

(defun while_loop () 
  (print
    (cond ((= factor 1) 
           (for_loop)
           (setf cycle_size (* cycle_size 2))
           (setf x_fixed x) 
           (setf count 1)
           (while_loop))

          ((/= factor 1) "The factor is : ")))
  (print factor))

(defun for_loop () 
    (cond ((and (<= count cycle_size) (<= factor 1)) 
           (setf x (rem (* x (+ x 1)) n)) 
           (setf factor (gcd (- x x_fixed) n)))
          ((or (<= count cycle_size) (<= factor 1)) 
           (setf count (+ count 1)) (for_loop))))

Notes

  • I named all variables and constants the same as in the C++ version.
  • I took half a day to decide whether or not to ask this question
  • If my Common Lisp code looks funny or silly you free to not-help
Subham Burnwal
  • 310
  • 2
  • 17
  • 1
    downvoters please give a reason if you have one, if its right then only helps me to improve – Subham Burnwal Mar 19 '18 at 02:13
  • 1
    Clisp is an implementation. The language is called Common Lisp, abbreviated CL. – Rainer Joswig Mar 19 '18 at 06:44
  • i will remember that – Subham Burnwal Mar 19 '18 at 07:15
  • 2
    There are a lot of undeclared variables in your code. For example all variables in PRIME are undeclared and unknown to Lisp. As such they would be global variables - but what it exactly does is even undefined in Common Lisp. – Rainer Joswig Mar 19 '18 at 10:58
  • thats confusing. how can they be unknown to lisp when they are global variables? I know by my 3-days' experience that any variables initialised(i cant remember anyother term) by setq can be accessed in other functions. Does using the helper functions inside prime as lambda, help in solving scope issues? I mean lambda functions can always access and modify their parent's variables, generally, right? – Subham Burnwal Mar 19 '18 at 18:50
  • Setting undefined variables with SETQ? Don't. SETQ sets variables, but it does not define them. Basically all your use of variables is broken. You need to define variables in C and you need to define variables in CL. – Rainer Joswig Mar 19 '18 at 18:53
  • "they are global variables"? Since you have not defined these variables, it's actually unclear what they are. – Rainer Joswig Mar 19 '18 at 18:54
  • "lambda functions can always access and modify their parent's variables". What is a parent of a lambda function? Lisp does not have the concept of a 'parent'. – Rainer Joswig Mar 19 '18 at 18:55
  • i meant the function which has the lambda inside it. i used that term since i cant recall the Lisp term for it sir – Subham Burnwal Mar 19 '18 at 19:08
  • None of your functions has a lambda inside. – Rainer Joswig Mar 19 '18 at 19:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167115/discussion-between-subham-and-rainer-joswig). – Subham Burnwal Mar 19 '18 at 19:36

2 Answers2

5

You need to define local variables.

A basic translation of the C code would look similar to this:

(defun my-gcd (a b)
  (let ((remainder 0))
    (loop while (/= b 0) do
          (setf remainder (mod a b)
                a b
                b remainder))
    a))

or with type declarations:

(defun my-gcd (a b)
  (declare (integer a b))
  (let ((remainder 0))
    (declare (integer remainder))
    (loop while (/= b 0) do
          (setf remainder (mod a b)
                a b
                b remainder))
    a))

The integer data type in Common Lisp is unbounded - unlike an int in C++.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • I found GCD already defined in CL, still i redefined it and it works, it doesnt use loop since the book i am following is explaining recursion before loops, so i have not yet reached that part yet. declaration of variables is still faraway but I guess i can handle it given how much I am comfortable with programing, I guess I need to change my book. thx again – Subham Burnwal Mar 19 '18 at 18:18
3

You really need to do more reading on Common Lisp. It has all the basic imperative constructs of C++, so there's no need to go through the contortions you have just to translate a simple algorithm. See for example Guy Steele's classic, available for free.

Here is a more reasonable and idiomatic trans-coding:

(defun prime-factor (n &optional (x 2))
  (let ((x-fixed x)
        (cycle-size 2)
        (factor 1))
    (loop while (= factor 1)
      do (loop for count from 1 to cycle-size
           while (<= factor 1)
           do (setq x (rem (1+ (* x x)) n)
                    factor (gcd (- x x-fixed) n)))
         (setq cycle-size (* 2 cycle-size)
               x-fixed x)))
    factor))

(defun test ()
  (prime-factor 10403))
Gene
  • 46,253
  • 4
  • 58
  • 96
  • sure sir I understand I have a lot to read, but is a transcode for the above program too complex to do with what I know now? I mean recursion... Just asking – Subham Burnwal Mar 19 '18 at 03:02
  • 2
    No. It can be done with recursion, but it's cumbersome. CL isn't Scheme. It's conventional to use a loop when a loop makes more sense. Additionally, it's my experience that CL compilers will do a better job optimizing loops than equivalent recursion. – Gene Mar 19 '18 at 03:45
  • 2
    you don't need the progn inside the LOOP after a DO. – Rainer Joswig Mar 19 '18 at 08:59
  • @RainerJoswig Thanks. I'm rusty. The last time I wrote CL in earnest was 1996. – Gene Mar 21 '18 at 02:24