Complex math made simple

Richard Suchenwirth 1998-10-27 - This little fun project deals with complex numbers, which have a real and an imaginary component, where i=sqrt(-1). In Tcl, I represent them very conventionally as strings like this:

  -1.23+4.56i

where -1.23 is the real and 4.56 the imaginary component. Conversion from/to this string rep and a list of {real imaginary} is done with

   complex::scan (string)
   complex::format (real) (im)

The imaginary factor may be an empty string if it amounts to 1 (e.g. 2+i), but must be signed with "+" or "-". For the rest, just see for yourself...}

Code

 namespace eval complex {
    proc scan s {
        regexp {^(-?([0-9]*\.)?[0-9]+)?(([+-]([0-9]*\.)?[0-9]*)i)?$} $s -> re - - im
        if {$re==""} {set re 0}
        switch -- $im {
            "" {set im 0}
            +  {set im 1}
            -  {set im -1}
        }
        list $re [expr {$im}] ;# expr may strip a plus sign
    }
    proc format {re {im 0}} {
        if {!$im} {return $re}
        subst $re[signof $im][expr {abs($im)==1?"":abs($im)}]i
    }
    proc signof x {expr {$x<0?"-":"+"}}
    proc re  x {lindex [scan $x] 0}
    proc im  x {lindex [scan $x] 1}
    proc abs x {expr hypot([join [scan $x] ,])} ;# no bracing with join
    proc + {x y} {
        lassign [scan $x] a b
        lassign [scan $y] c d
        format [expr {$a+$c}] [expr {$b+$d}]
    }
    proc - {x y} {
        lassign [scan $x] a b
        lassign [scan $y] c d
        format [expr {$a-$c}] [expr {$b-$d}]
    }
    proc * {x y} {
        lassign [scan $x] a b
        lassign [scan $y] c d
        format [expr {$a*$c-$b*$d}] [expr {$a*$d+$b*$c}]
    }
    proc / {x y} {
        lassign [scan $x] a b
        lassign [scan $y] c d
        set div [expr {double($c*$c+$d*$d)}]
        format [expr {($a*$c+$b*$d)/$div}] [expr {($b*$c-$a*$d)/$div}]
    }

Examples

    proc test {} {
      foreach test [split {
        scan    1.23+4.56i
        scan   -1.35
        format  1.23 4.56
        format -1.23 -4.56
        re  -47.1-11i
        im  -1.23+4.56i
        abs  3+4i
        +    3+i   1+2i
        -    3+i   1+2i
        \*    3+4i  1+2i
        \*    +i    +i ;# -1
        /    2+5i -6-2i
      } \n] {
        puts -nonewline "$test => "
        puts [eval $test]
      }
   }
 }

 puts [time complex::test 10] ;# took 91..121 msec on my P2/200/W95/8.1a2

AM Here is a Straightforward implementation of complex numbers, aimed at practical use (that is: it expects complex numbers to be in preprocessed form)


Years later, RS redid it much simpler in Complex math with TOOT