[Arjen Markus] (12 may 2004) Complex numbers fascinate me in a peculiar way - in my professional life I very rarely have to deal with them, unfortunately, but they make certain mathematical problems much and much easier. Oh well, here is a script that implements complex numbers as lists of two floating-point numbers. By assuming the preprocessing step has been done, the procedures can be very short and fast. ---- # qcomplex.tcl -- # Small module for dealing with complex numbers # The design goal was to make the operations as fast # as possible, not to offer a nice interface. So: # - complex numbers are represented as lists of two elements # - there is hardly any error checking, all arguments are assumed # to be complex numbers already (with a few obvious exceptions) # Missing: # the inverse trigonometric functions and the hyperbolic functions # namespace eval ::math::complex { namespace export + - / * conj exp sin cos tan real imag mod arg log pow sqrt tostring } # complex -- # Create a new complex number # Arguments: # real The real part # imag The imaginary part # Result: # New complex number # proc ::math::complex::complex {real imag} { return [list $real $imag] } # binary operations -- # Implement the basic binary operations # Arguments: # z1 First argument # z2 Second argument # Result: # New complex number # proc ::math::complex::+ {z1 z2} { set result {} foreach c $z1 d $z2 { lappend result [expr {$c+$d}] } return $result } proc ::math::complex::- {z1 {z2 {}}} { if { $z2 == {} } { set z2 $z1 set z1 {0.0 0.0} } set result {} foreach c $z1 d $z2 { lappend result [expr {$c-$d}] } return $result } proc ::math::complex::* {z1 z2} { set result {} foreach {c1 d1} $z1 {break} foreach {c2 d2} $z2 {break} return [list [expr {$c1*$c2-$d1*$d2}] [expr {$c1*$d2+$c2*$d1}]] } proc ::math::complex::/ {z1 z2} { set result {} foreach {c1 d1} $z1 {break} foreach {c2 d2} $z2 {break} set denom [expr {$c2*$c2+$d2*$d2}] return [list [expr {($c1*$c2+$d1*$d2)/$denom}] \ [expr {(-$c1*$d2-$c2*$d1)/$denom}]] } # unary operations -- # Implement the basic unary operations # Arguments: # z1 Argument # Result: # New complex number # proc ::math::complex::conj {z1} { foreach {c d} $z1 {break} return [list $c [expr {-$d}]] } proc ::math::complex::real {z1} { foreach {c d} $z1 {break} return $c } proc ::math::complex::imag {z1} { foreach {c d} $z1 {break} return $d } proc ::math::complex::mod {z1} { foreach {c d} $z1 {break} return [expr {hypot($c,$d)}] } proc ::math::complex::arg {z1} { foreach {c d} $z1 {break} if { $c != 0.0 || $d != 0.0 } { return [expr {atan2($d,$c)}] } else { return 0.0 } } # elementary functions -- # Implement the elementary functions # Arguments: # z1 Argument # z2 Second argument (if any) # Result: # New complex number # proc ::math::complex::exp {z1} { foreach {c d} $z1 {break} return [list [expr {exp($c)*cos($d)}] [expr {exp($c)*sin($d)}]] } proc ::math::complex::cos {z1} { foreach {c d} $z1 {break} return [list [expr {cosh($c)*cos($d)}] [expr {sinh($c)*sin($d)}]] } proc ::math::complex::sin {z1} { foreach {c d} $z1 {break} return [list [expr {sinh($c)*cos($d)}] [expr {cosh($c)*sin($d)}]] } proc ::math::complex::tan {z1} { return [/ [sin $z1] [cos $z1]] } proc ::math::complex::log {z1} { return [list [expr {log([mod $z1])}] [arg $z1]] } proc ::math::complex::sqrt {z1} { set argz [expr {0.5*[arg $z1]}] set modz [expr {sqrt([mod $z1])}] return [list [expr {$modz*cos($argz)}] [expr {$modz*sin($argz)}]] } proc ::math::complex::pow {z1 z2} { return [exp [* [log $z1] $z2]] } # transformational functions -- # Implement transformational functions # Arguments: # z1 Argument # Result: # String like 1+i # proc ::math::complex::tostring {z1} { foreach {c d} $z1 {break} if { $d == 0.0 } { return "$c" } else { if { $c == 0.0 } { if { $d == 1.0 } { return "i" } else { return "${d}i" } } else { if { $d > 0.0 } { return "$c+${d}i" } else { if { $d == -1.0 } { return "$c-i" } else { return "$c${d}i" } } } } } # # Some tests # namespace import ::math::complex::* set a [complex 1 0] set b [complex 0 1] set c [complex -1 0] puts "a = [tostring $a]; b = [tostring $b]; c = [tostring c]" puts "a+b= [+ $a $b] (= 1 1)" puts "a-b= [- $a $b] (= 1 -1)" puts "-a = [- $a] (= -1 0)" puts "a*a = [* $a $a] (= 1 0)" puts "b*b = [* $b $b] (= -1 0)" puts "a/b = [/ $a $b] (= 0 -1)" puts "exp(a) = [exp $a] (= e 0)" puts "exp(b) = [exp $b] (= cos(1) sin(1))" puts "cos(b) = [cos $b]" puts "sin(b) = [sin $b]" puts "tan(b) = [tan $b]" puts "conj(b) = [conj $b] (= 0 -1)" puts "mod(b) = [mod $b] (= 1)" puts "arg(b) = [arg $b] (= pi/2)" puts "real(b) = [real $b] (= 0)" puts "imag(b) = [imag $b] (= 1)" puts "sqrt(c) = [sqrt $c] (= 0 1)" puts "log(c) = [log $c] (= 0 pi)" puts "tostring(0 1) = [tostring {0 1}] (= i)" puts "tostring(1 -1) = [tostring {1 -1}] (= 1-i)" puts "tostring(1 0) = [tostring {1 0}] (= 1)" puts "pow(1,10i) = [pow {1 0} {0 10}] (= 1)" puts "pow(i,i) = [pow {0 1} {0 1}] (= e**(-pi/2))" puts "exp(i*pi) = [exp [list 0 [expr {acos(-1)}]]] (= -1)" ---- See also [Complex math made simple] ---- [[ [Category Mathematics] ]]