Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Complex numbers.

View Complex.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
package com.czechscala.blank
 
class Complex(val r: Double, val i: Double) {
 
def this(coord: Tuple2[Double, Double]) = this(
coord._1 * Math.cos(coord._2),
coord._1 * Math.sin(coord._2)
)
 
def +(other: Complex) = new Complex(r + other.r, i + other.i)
 
def -(other: Complex) = new Complex(r - other.r, i - other.i)
 
def *(other: Complex) = new Complex(
r * other.r - i * other.i,
i * other.r + r * other.i
)
 
def /(other: Complex) = new Complex(
(r * other.r + i * other.i) / (other.r * other.r + other.i * other.i),
(i * other.r - r * other.i) / (other.r * other.r + other.i * other.i)
)
 
override def equals(obj: scala.Any) = obj match {
case that: Complex => Math.abs((r - that.r) / r) <= 0.001 && Math.abs((i - that.i) / i) <= 0.001
case _ => false
}
 
override def toString = {
val sign = if (i < 0) '-' else '+'
s"($r $sign ${Math.abs(i)}i)"
}
}
View Complex.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
package com.czechscala.blank
 
import org.scalatest.FunSuite
 
class ComplexTest extends FunSuite {
 
trait ComplexTrait {
val c1 = new Complex(1, 2)
val c2 = new Complex(3, 4)
}
 
test("constructor") {
val comp = new Complex(1, 2)
assert(comp.r === 1)
assert(comp.i === 2)
}
 
test("simple adding") {
new ComplexTrait {
val c3 = new Complex(4, 6)
assert(c1 + c2 === c3)
}
}
 
test("simple subtraction") {
new ComplexTrait {
val c3 = new Complex(-2, -2)
assert(c1 - c2 === c3)
}
}
 
test("simple multiplication") {
new ComplexTrait {
val c3 = new Complex(-5, 10)
assert(c1 * c2 === c3)
}
}
 
test("simple division") {
new ComplexTrait {
val c3 = new Complex(0.44, 0.08)
assert(c1 / c2 === c3)
}
}
 
test("toString") {
new ComplexTrait {
assert(c1.toString === "(1.0 + 2.0i)")
assert(new Complex(-1, 2).toString === "(-1.0 + 2.0i)")
assert(new Complex(-1, -2).toString === "(-1.0 - 2.0i)")
}
}
 
test("equals") {
new ComplexTrait {
assert(c1 == new Complex(c1.r, c1.i))
assert(c1 != c2)
assert(c1 != new Object())
assert(c1 != true)
assert(new Complex(1.00001, 1.00004) == new Complex(1, 1))
}
}
 
test("construct with polar coordinates") {
val c = new Complex((5, 0.92729))
assert(c === new Complex(3, 4))
assert(c != new Complex(3, 40))
}
}

Mám tu dvě poznámky. K první doporučuji si něco najít o case classes, hodí se skoro všude. Druhá poznámka bude zajímavá až při řešení syntaxe typu 2+3.i.

  1. Metoda equals by šla vyřešit pomocí case classes - začátek deklarace třídy by byl case class Complex(r: Double, i: Double) a dostali byste "zdarma" metodu equals plus další metody (např. hashCode, na které jste zapomněli).

  2. Tady to zatím není moc vidět, ale pokud bychom chtěli umožnit zápis 3+2.i, museli bychom udělat dvě* implicitní konverze (řekněme realToComplex pro operace mezi reálnými a komplexními čísly a k tomu realComplexConversions pro výraz 2.i) hodilo by se přejmenovat field i na něco jiného. Jinak by asi vznikla nejednoznačnost u implicitních konverzí - 2.i by se mohlo vyhodnotit
    a) buď jako realToComplex(2).i (tedy by se to snažilo zjistit imaginární složku z dvojky, která by samozřejmě byla nulová, tedy 0.0)
    b) nebo jako realComplexConversions(2).i, což by mělo vrátit Complex(0, 2).

*) OK, zanedbávám, že reálné číslo může být vyjádřeno nejen typem Double, ale i Float nebo dokonce Int apod. Pro zjednodušení.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.