-2

The code below is the answer given by the professor for a question in my intro to scheme course but it comes out with an error. Cannot see why.

#!r5rs

(define (make-complex a b) (cons a b))
(define (real x) (car x))
(define (imag x) (cdr x))

(define (complex-sqrt x)
  (define (sgn v)
    (cond ((< v 0) -1)
          ((= v 0) 0)
          (else 1)))
  (let ((root (sqrt (+ (* (real x) (real x))
                       (* (imag x) (imag x))))))
    (make-complex (sqrt (/ (+ (real x) root) 2))
                  (*  (sgn (imag x))
                      (sqrt (/ (- root (real x)) 2))))))

(complex-sqrt 7)
;; ERROR mcar: contract violation
;; expected: mpair? 
;; given: 7

I took a screenshot of the error with trace illustartion while running it in DrRacket.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
Michael C
  • 1
  • 1

2 Answers2

0

Here's your code transcribed. Please consider posting the actual code rather than a screenshot in future.

(define (make-complex a b) (cons a b))
(define (real x) (car x))
(define (imag x) (cdr x))

(define (complex-sqrt x)
    (define (sgn v)
        (cond ((< v 0) -1)
              ((= v 0) 0)
              (else 1)))
    (let ((root (sqrt (+ (* (real x) (real x))
                         (* (imag x) (imag x))))))
         (make-complex (sqrt (/ (+ (real x) root) 2))
                       (*  (sgn (imag x))
                           (sqrt (/ (- root (real x)) 2))))))

Was the (complex-sqrt 7) part provided by your professor too? We're trying to get the square root of a complex number, so we should pass in a complex number:

(complex-sqrt (make-complex 5 2))
'(2.27872385417085 . 0.43884211690225433)

Which according to https://www.wolframalpha.com/input/?i=sqrt(2i%2B5) is correct!

sneep
  • 1,828
  • 14
  • 19
0

The implementation of complex-sqrt is an unsafe one. What that means is that it assumes you pass it a complex number, in this case something created with make-complex.

To fix this you need to check if the argument is complex:

;; Not 100%. Should use `struct` to not
;; mix with random pairs that happens to have numeric parts
(define (complex? x)
  (and (pair? x)
       (number? (car x))
       (number? (cdr x))))


;; The original code is renamed to unsafe-complex-sqrt
(define (complex-sqrt x)
  (if (complex? x)
      (unsafe-complex-sqrt x)      
      (raise-argument-error 'complex-sqrt "complex?" x)))

Now you can test it:

(complex-sqrt (make-complex 7 0)) 
; ==> (2.6457513110645907 . 0)

(complex-sqrt 7)
; ERROR complex-sqrt: contract violation
; expected: complex?
; given: 7

Perfect. Now it says you have mot passed the required complex number to a function that requires a complex number to work.

So what happend in the original code? In unsafe-complex-sqrt it uses car and cdr which are safe operations that signal contract violation if the argument x supplied isn't #t for (pair? x).

Racket uses mcons in its #!r5rs implementation and thus the errors refer to every pair/list function in R5RS prefixed with an m since the error doesn't pay attention to renaming.

Sylwester
  • 47,942
  • 4
  • 47
  • 79