Complex numbers (Scala)
From LiteratePrograms
This article presents an set of classes for representing complex numbers in the Scala multiparadigm programming language.
Contents |
Representation
We will represent a complex number with the abstract Complex class. This class includes accessors to query the complex number, as well as basic arithmetic functions.
We provide two concrete subclasses to construct a complex number either with its rectangular coordinates (RectComplex) or its polar coordinates (PolarComplex). Except for their constructor, which behaves differently, these classes share exactly the same behavior.
Note that these complex numbers are immutable.
<<ComplexNumber.scala>>= package complex class Complex { accessors arithmetic conjugate } rectangle initialization polar initialization
Accessors
The accessors are defined in the Complex abstract base class.
<<accessors>>= val real: double val imag: double val magnitude: double val angle: double
Initialization
Initialization is done in the concrete subclasses.
<<rectangle initialization>>= class RectComplex(r: double, i: double) extends Complex { val real = r val imag = i val magnitude = Math.sqrt(r*r + i*i) val angle = Math.atan2(i, r) } <<polar initialization>>= class PolarComplex(m: double, a: double) extends Complex { val real = m * Math.cos(a) val imag = m * Math.sin(a) val magnitude = m val angle = a }
Arithmetic
Core arithmetic operations provided are addition, subtraction, multiplication, division. The arithmetic operations are defined in the abstract Complex base class.
<<arithmetic>>= addition subtraction multiplication division
Addition and Subtraction
Addition and subtraction are implemented using the coordinate representation:
<<addition>>= def +(that: Complex) = new RectComplex(real + that.real, imag + that.imag) <<subtraction>>= def -(that: Complex) = new RectComplex(real - that.real, imag - that.imag)
Multiplication and Division
Multiplication and division are implemented using the polar representation:
<<multiplication>>= def *(that: Complex) = new PolarComplex(magnitude * that.magnitude, angle + that.angle) <<division>>= def /(that: Complex) = new PolarComplex(magnitude / that.magnitude, angle - that.angle)
Complex Conjugate
<<conjugate>>= def conjugate = new RectComplex(real, -imag)
Test
Here where test our complex numbers. As you can see the code is much longer than our complex number implementation itself.
<<ComplexTestSuite.scala>>= package complex test initialization test util test rectangular constructor test polar constructor test addition test subtraction test multiplication test division test conjugate test run
Test Initialization
<<test initialization>>= import scala.testing.SUnit._ val tr = new TestResult val tolerance = 0.000001
Test Util
A util base class for the individual test objects.
<<test util>>= abstract class UtilTest(title: String) extends TestCase(title) with Assert { def assertInDelta(exp: double, found: double) = { val delta = Math.abs(exp - found) if (delta > tolerance) fail("Expected delta to be less than " + tolerance + ". Was " + delta) } }
Test Rectangular Constructor
<<test rectangular constructor>>= object RectConstructorTest extends UtilTest("Testing rectangular complex number constructor") { override def runTest = { val c = new RectComplex(1, 1) assertEquals(1, c.real) assertEquals(1, c.imag) assertInDelta(Math.sqrt(2.0), c.magnitude) assertInDelta(Math.Pi / 4, c.angle) } }
Test Polar Constructor
<<test polar constructor>>= object PolarConstructorTest extends UtilTest("Testing polar complex number constructor") { override def runTest = { val c = new PolarComplex(1, Math.Pi / 4) assertInDelta(Math.sqrt(2.0) / 2, c.real) assertInDelta(Math.sqrt(2.0) / 2, c.imag) assertEquals(1, c.magnitude) assertEquals(Math.Pi / 4, c.angle) } }
Test Addition
<<test addition>>= object AdditionTest extends UtilTest("Testing complex addition") { override def runTest = { val z1 = new RectComplex(1, 2) val z2 = new RectComplex(3, 4) val z3 = z1 + z2 assertEquals(1 + 3, z3.real) assertEquals(2 + 4, z3.imag) } }
Test Subtraction
<<test subtraction>>= object SubractionTest extends UtilTest("Testing complex subtraction") { override def runTest = { val z1 = new RectComplex(1, 2) val z2 = new RectComplex(3, 4) val z3 = z1 - z2 assertEquals(1 - 3, z3.real) assertEquals(2 - 4, z3.imag) } }
Test Multiplication
<<test multiplication>>= object MultiplicationTest extends UtilTest("Testing complex multiplication") { override def runTest = { val z1 = new PolarComplex(1, Math.Pi / 3) val z2 = new PolarComplex(3, Math.Pi / 6) val z3 = z1 * z2 assertEquals(1 * 3, z3.magnitude) assertEquals(Math.Pi / 2, z3.angle) } }
Test Division
<<test division>>= object DivisionTest extends UtilTest("Testing complex division") { override def runTest = { val z1 = new PolarComplex(1, Math.Pi / 3) val z2 = new PolarComplex(2, Math.Pi / 6) val z3 = z1 / z2 assertEquals(1.0 / 2, z3.magnitude) assertEquals(Math.Pi / 6, z3.angle) } }
Test Conjugate
<<test conjugate>>= object ConjugateTest extends UtilTest("Testing complex conjugate") { override def runTest = { val z = new RectComplex(1, 2).conjugate assertEquals(1, z.real) assertEquals(-2, z.imag) } }
Test Run
<<test run>>= new TestSuite(RectConstructorTest, PolarConstructorTest, AdditionTest, SubractionTest, MultiplicationTest, DivisionTest, ConjugateTest ).run(tr) for(f <- tr.failures) { println(f) }
| Download code |
