; complex.lisp - prototype implementation of complex numbers
;
; Copyright (C) 2026 by Jef Poskanzer <jef@mail.acme.com>.
; All rights reserved.
;
; You may use this software however you like as long as you keep my
; name on it and don't sue me.
;
; For commentary on this license please see http://acme.com/license.html
;
;
; Complex numbers are represented by a CONS pair of two NUMs.

(defun complex ("number" r "number" i)
    (cons r i)
)
(doc 'complex "Makes a complex number.")

(defun complex-r ("cons" c) (car c))
(doc 'complex-r "Returns the real part of a complex number.")

(defun complex-i ("cons" c) (cdr c))
(doc 'complex-i "Returns the imaginary part of a complex number.")

(defun complex-tostring ("cons" c)
    (letrec
	(ipart
	    (lambda ("string" prefix "number" i)
		(cond
		    ((negative? i) (ipart "-" (abs i)))
		    ((= i 0) "")
		    ((= i 1) (string-concat prefix "i"))
		    (t (string-concat prefix (string i) "i"))
		)
	    )
	)
	(cond
	    ((and (= (complex-r c) 0) (= (complex-i c) 0)) "0")
	    ((= (complex-r c) 0) (ipart "" (complex-i c)))
	    (t (string-concat (string (complex-r c)) (ipart "+" (complex-i c))))
	)
    )
)
(doc 'complex-tostring "Converts a complex to a string.")

; Add an sprintf formatter for complex numbers as %c.
(sprintf-add 'c' cons? complex-tostring)

(defun complex-add ("cons" c1 "cons" c2)
    (complex
	(+ (complex-r c1) (complex-r c2))
	(+ (complex-i c1) (complex-i c2))
    )
)
(doc 'complex-add "Adds two complex numbers.")

(defun complex-negate ("cons" c)
    (complex (negate (complex-r c)) (negate (complex-i c)))
)
(doc 'complex-negate "Returns the negative of a complex number.")

(defun complex-subtract ("cons" c1 "cons" c2) (complex-add c1 (complex-negate c2)))
(doc 'complex-subtract "Subtracts one complex number from another.")

(defun complex-multiply ("cons" c1 "cons" c2)
    (complex
	(- (* (complex-r c1) (complex-r c2)) (* (complex-i c1) (complex-i c2)))
	(+ (* (complex-r c1) (complex-i c2)) (* (complex-i c1) (complex-r c2)))
    )
)
(doc 'complex-multiply "Multiplies two complex numbers.")

(defun complex-conjugate ("cons" c)
    (complex (complex-r c) (negative (complex-i c)))
)
(doc 'complex-conjugate "Returns the conjugate of a complex nmumber.")

(defun complex-reciprocal ("cons" c)
    (let*
	(ss (+ (* (square (complex-r c))) (* (square (complex-i c)))))
	(complex
	    (/ (complex-r c) ss)
	    (/ (complex-i c) ss)
	)
    )
)
(doc 'complex-reciprocal "Returns the reciprocal of a complex nmumber.")

(defun complex-divide ("cons" c1 "cons" c2)
    (complex-multiply c1 (complex-reciprocal c2))
)
(doc 'complex-divide "Divides one complex number by another.")
