GPS: Arjen and Richard come up with interesting contraptions. I hadn't heard of complex numbers before this page, and I suspect many others have not as well. To that end I found this page useful: http://www.clarku.edu/~djoyce/complex/plane.htmlFor some reason this reminds me of Funge.
AM Fixed a small bug in [cos], noted by Oscar Andres Lopez] (26 october 2005)
# 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::complexnumbers { 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::complexnumbers::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::complexnumbers::+ {z1 z2} { set result {} foreach c $z1 d $z2 { lappend result [expr {$c+$d}] } return $result } proc ::math::complexnumbers::- {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::complexnumbers::* {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::complexnumbers::/ {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::complexnumbers::conj {z1} { foreach {c d} $z1 {break} return [list $c [expr {-$d}]] } proc ::math::complexnumbers::real {z1} { foreach {c d} $z1 {break} return $c } proc ::math::complexnumbers::imag {z1} { foreach {c d} $z1 {break} return $d } proc ::math::complexnumbers::mod {z1} { foreach {c d} $z1 {break} return [expr {hypot($c,$d)}] } proc ::math::complexnumbers::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::complexnumbers::exp {z1} { foreach {c d} $z1 {break} return [list [expr {exp($c)*cos($d)}] [expr {exp($c)*sin($d)}]] } proc ::math::complexnumbers::cos {z1} { foreach {c d} $z1 {break} return [list [expr {cos($c)*cosh($d)}] [expr {-sin($c)*sinh($d)}]] } proc ::math::complexnumbers::sin {z1} { foreach {c d} $z1 {break} return [list [expr {sin($c)*cosh($d)}] [expr {cos($c)*sinh($d)}]] } proc ::math::complexnumbers::tan {z1} { return [/ [sin $z1] [cos $z1]] } proc ::math::complexnumbers::log {z1} { return [list [expr {log([mod $z1])}] [arg $z1]] } proc ::math::complexnumbers::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::complexnumbers::pow {z1 z2} { return [exp [* [log $z1] $z2]] } # transformational functions -- # Implement transformational functions # Arguments: # z1 Argument # Result: # String like 1+i # proc ::math::complexnumbers::tostring {z1} { foreach {c d} $z1 {break} if { $d == 0.0 } { return "$c" } else { if { $c == 0.0 } { if { $d == 1.0 } { return "i" } elseif { $d == -1.0 } { return "-i" } else { return "${d}i" } } else { if { $d > 0.0 } { if { $d == 1.0 } { return "$c+i" } else { return "$c+${d}i" } } else { if { $d == -1.0 } { return "$c-i" } else { return "$c${d}i" } } } } } # # Some tests # namespace import ::math::complexnumbers::* 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 - Complex math with TOOT
AM Recent discussions regarding the possibility to expand [expr] to take more data types into account, complex numbers for instance or vector-valued variables have led me to create two new pages: On mathematical notation - a very nice overview by Lars Hellstrom, and as I was inspired by the solution he proposed, Vector spaces.AM (17 october 2017) Working with the TclODE package I realised that I could simply use the code from the math::symdiff module in Tcllib to create an easy-to-use command that takes the classical mathematical notation and turns it into the prefix notation required here. The advantage is the more familiar infix notation can be used, the downside is that the code is slower. Anyway, worth an extension to the Tcllib module. Coming soon.