Permalink
Browse files

Start using Trig[A] type class in Complex[A].

This removes some situations where we were losing
precision in complex numbers, which will help when
using types more precise than Double.

The one remaining place where we convert to Double
is where we need to do A ** A (since Field only
supports A ** Int). It would be nice to be able
to add pow(A, A) to Field someday.
  • Loading branch information...
1 parent 17525eb commit 3de50729e4c9efae23292d3801c93fa94f909cdc @non committed Apr 18, 2012
@@ -26,7 +26,7 @@ object EuclideanRing {
implicit object BigDecimalIsEuclideanRing extends BigDecimalIsEuclideanRing
implicit object RationalIsEuclideanRing extends RationalIsEuclideanRing
implicit object RealIsEuclideanRing extends RealIsEuclideanRing
- implicit def complexIsEuclideanRingCls[A:Fractional] = new ComplexIsEuclideanRingCls
+ implicit def complexIsEuclideanRingCls[A:Fractional:Trig] = new ComplexIsEuclideanRingCls
def apply[A](implicit e:EuclideanRing[A]):EuclideanRing[A] = e
}
@@ -88,4 +88,4 @@ extends ComplexIsRing[A] with EuclideanRing[Complex[A]] {
}
class ComplexIsEuclideanRingCls[@spec(Float,Double) A]
-(implicit val f:Fractional[A]) extends ComplexIsEuclideanRing[A]
+(implicit val f:Fractional[A], val t:Trig[A]) extends ComplexIsEuclideanRing[A]
@@ -9,6 +9,10 @@ trait Field[@spec(Int,Long,Float,Double) A] extends EuclideanRing[A] {
def isWhole(a:A): Boolean
def reciprocal(a:A): A = div(one, a)
+ // TODO
+ // def exp(a:A)
+ // def log(a:A)
+
override def multiplicative:Group[A] = new MultiplicativeGroup[A]()(this)
}
@@ -23,7 +27,7 @@ object Field {
implicit object BigDecimalIsField extends BigDecimalIsField
implicit object RationalIsField extends RationalIsField
implicit object RealIsField extends RealIsField
- implicit def complexIsField[A:Fractional] = new ComplexIsFieldCls
+ implicit def complexIsField[A:Fractional:Trig] = new ComplexIsFieldCls
def apply[A](implicit f:Field[A]):Field[A] = f
}
@@ -61,5 +65,5 @@ extends ComplexIsEuclideanRing[A] with Field[Complex[A]] {
}
class ComplexIsFieldCls[@spec(Float,Double) A]
-(implicit val f:Fractional[A]) extends ComplexIsField[A]
+(implicit val f:Fractional[A], val t:Trig[A]) extends ComplexIsField[A]
@@ -68,7 +68,7 @@ object Ring {
implicit object BigIntIsRing extends BigIntIsRing
implicit object BigDecimalIsRing extends BigDecimalIsRing
implicit object RationalIsRing extends RationalIsRing
- implicit def complexIsRing[A:Fractional] = new ComplexIsRingCls
+ implicit def complexIsRing[A:Fractional:Trig] = new ComplexIsRingCls
implicit object RealIsRing extends RealIsRing
def apply[A](implicit r:Ring[A]):Ring[A] = r
@@ -196,15 +196,16 @@ trait RationalIsRing extends Ring[Rational] {
}
trait ComplexIsRing[A] extends Ring[Complex[A]] {
- implicit val f:Fractional[A]
+ implicit def f:Fractional[A]
+ implicit def t:Trig[A]
override def minus(a:Complex[A], b:Complex[A]): Complex[A] = a - b
def negate(a:Complex[A]): Complex[A] = -a
- def one: Complex[A] = Complex.one(f)
+ def one: Complex[A] = Complex.one(f, t)
def plus(a:Complex[A], b:Complex[A]): Complex[A] = a + b
override def pow(a:Complex[A], b:Int):Complex[A] = a.pow(Complex(f.fromInt(b), f.zero))
override def times(a:Complex[A], b:Complex[A]): Complex[A] = a * b
- def zero: Complex[A] = Complex.zero(f)
+ def zero: Complex[A] = Complex.zero(f, t)
override def fromInt(n: Int): Complex[A] = Complex(f.fromInt(n), f.zero)
}
@@ -221,5 +222,5 @@ trait RealIsRing extends Ring[Real] {
override def fromInt(n: Int): Real = Real(n)
}
-class ComplexIsRingCls[A](implicit val f:Fractional[A])
+class ComplexIsRingCls[A](implicit val f:Fractional[A], val t:Trig[A])
extends ComplexIsRing[A]
@@ -1,6 +1,6 @@
package spire.algebra
-import spire.math.{ Fractional, Order, Real, Rational, Complex }
+import spire.math.{Fractional, Trig, Order, Real, Rational, Complex}
import scala.{ math => mth }
import scala.{ specialized => spec }
@@ -37,8 +37,7 @@ object Signed extends SignedLow {
implicit object BigDecimalIsSigned extends BigDecimalIsSigned
implicit object RationalIsSigned extends RationalIsSigned
implicit object RealIsSigned extends RealIsSigned
- implicit def ComplexIsSigned[A](implicit fr: Fractional[A]) =
- new ComplexIsSigned[A] { val f = fr }
+ implicit def ComplexIsSigned[A:Fractional:Trig] = new ComplexIsSignedCls
def apply[A](implicit s: Signed[A]): Signed[A] = s
}
@@ -117,9 +116,12 @@ trait RealIsSigned extends Signed[Real] {
}
trait ComplexIsSigned[A] extends Signed[Complex[A]] {
- implicit val f:Fractional[A]
+ implicit def f:Fractional[A]
+ implicit def t:Trig[A]
override def signum(a: Complex[A]): Int = a.signum
- def abs(a: Complex[A]): Complex[A] = Complex[A](a.abs, f.zero)(f)
+ def abs(a: Complex[A]): Complex[A] = Complex[A](a.abs, f.zero)
}
+class ComplexIsSignedCls[A](implicit val f:Fractional[A], val t:Trig[A])
+extends ComplexIsSigned[A]
@@ -13,25 +13,25 @@ import Implicits._
// access functions (e.g. trig, pow, exp, log)
object Complex {
- def i[@spec(Float, Double) T](implicit f:Fractional[T]) = Complex(f.zero, f.one)
- def one[@spec(Float, Double) T](implicit f:Fractional[T]) = Complex(f.one, f.zero)
- def zero[@spec(Float, Double) T](implicit f:Fractional[T]) = Complex(f.zero, f.zero)
+ def i[@spec(Float, Double) T](implicit f:Fractional[T], t:Trig[T]) = Complex(f.zero, f.one)
+ def one[@spec(Float, Double) T](implicit f:Fractional[T], t:Trig[T]) = Complex(f.one, f.zero)
+ def zero[@spec(Float, Double) T](implicit f:Fractional[T], t:Trig[T]) = Complex(f.zero, f.zero)
implicit def intToComplex(n:Int) = new Complex(n.toDouble, 0.0)
implicit def longToComplex(n:Long) = new Complex(n.toDouble, 0.0)
- implicit def doubleToComplex(n:Float) = new Complex(n, 0.0F)
+ implicit def floatToComplex(n:Float) = new Complex(n, 0.0F)
implicit def doubleToComplex(n:Double) = new Complex(n, 0.0)
- def polar[@spec(Float, Double) T](magnitude:T, angle:T)(implicit f:Fractional[T]) = {
- val real:T = f.times(magnitude, f.fromDouble(cos(angle.toDouble)))
- val imag:T = f.times(magnitude, f.fromDouble(sin(angle.toDouble)))
+ def polar[@spec(Float, Double) T](magnitude:T, angle:T)(implicit f:Fractional[T], t:Trig[T]) = {
+ val real:T = f.times(magnitude, t.cos(angle))
+ val imag:T = f.times(magnitude, t.sin(angle))
Complex(real, imag)
}
- def apply[@spec(Float, Double) T:Fractional](real:T, imag:T) = new Complex(real, imag)
- def unapply[@spec(Float, Double) T:Fractional](c:Complex[T]) = Some((c.real, c.imag))
+ def apply[@spec(Float, Double) T:Fractional:Trig](real:T, imag:T) = new Complex(real, imag)
+ def unapply[@spec(Float, Double) T:Fractional:Trig](c:Complex[T]) = Some((c.real, c.imag))
}
-class Complex[@spec(Float, Double) T](val real:T, val imag:T)(implicit f:Fractional[T])
+class Complex[@spec(Float, Double) T](val real:T, val imag:T)(implicit f:Fractional[T], t:Trig[T])
extends ScalaNumber with ScalaNumericConversions with Serializable {
// ugh, ScalaNumericConversions ghetto
@@ -50,13 +50,15 @@ extends ScalaNumber with ScalaNumericConversions with Serializable {
this / Complex(abs, f.zero)
}
- override def hashCode: Int = if (isReal && real.isWhole &&
- real <= f.fromInt(Int.MaxValue) &&
- real >= f.fromInt(Int.MinValue)) {
- real.toInt.##
- } else {
- 19 * real.## + 41 * imag.##
- }
+ //override def hashCode: Int = if (isReal && real.isWhole &&
+ // real <= f.fromInt(Int.MaxValue) &&
+ // real >= f.fromInt(Int.MinValue)) {
+ // real.toInt.##
+ //} else {
+ // 19 * real.## + 41 * imag.##
+ //}
+
+ override def hashCode: Int = 19 * real.## + 41 * imag.##
override def equals(that: Any): Boolean = that match {
case that:Complex[_] => real == that.real && imag == that.imag
@@ -65,15 +67,11 @@ extends ScalaNumber with ScalaNumericConversions with Serializable {
override def toString: String = "Complex(%s, %s)".format(real, imag)
- // ugh, for very large Fractional values this will totally break
- //lazy val magnitude: T = f.sqrt(real * real + imag * imag)
- //lazy val angle: T = f.fromDouble(atan2(imag.toDouble, real.toDouble))
- //def abs: T = magnitude
- //def arg: T = angle
-
// ugh, specialized lazy vals don't work very well
+ //lazy val abs: T = f.sqrt(real * real + imag * imag)
+ //lazy val arg: T = t.atan2(imag, real)
def abs: T = f.sqrt(real * real + imag * imag)
- def arg: T = f.fromDouble(atan2(imag.toDouble, real.toDouble))
+ def arg: T = t.atan2(imag, real)
def conjugate = Complex(real, f.negate(imag))
@@ -141,6 +139,9 @@ extends ScalaNumber with ScalaNumericConversions with Serializable {
Complex.zero[T]
} else if (f.neqv(b.imag, f.zero)) {
+ // TODO: is adding frac**frac reasonable? if not, we won't be able to do
+ // this without something hacky like the below.
+ // TODO: we also need log and exp on Field, Fractional, or Trig.
val len = f.fromDouble(math.pow(abs.toDouble, b.real.toDouble) / exp((arg * b.imag).toDouble))
val phase = f.fromDouble(arg.toDouble * b.real.toDouble + log(abs.toDouble) * b.imag.toDouble)
Complex.polar(len, phase)
@@ -121,16 +121,17 @@ trait ConvertableToRational extends ConvertableTo[Rational] {
}
trait ConvertableToComplex[A] extends ConvertableTo[Complex[A]] {
- val f:Fractional[A]
- def fromByte(a:Byte): Complex[A] = Complex(f.fromByte(a), f.zero)(f)
- def fromShort(a:Short): Complex[A] = Complex(f.fromShort(a), f.zero)(f)
- def fromInt(a:Int): Complex[A] = Complex(f.fromInt(a), f.zero)(f)
- def fromLong(a:Long): Complex[A] = Complex(f.fromLong(a), f.zero)(f)
- def fromFloat(a:Float): Complex[A] = Complex(f.fromFloat(a), f.zero)(f)
- def fromDouble(a:Double): Complex[A] = Complex(f.fromDouble(a), f.zero)(f)
- def fromBigInt(a:BigInt): Complex[A] = Complex(f.fromBigInt(a), f.zero)(f)
- def fromBigDecimal(a:BigDecimal): Complex[A] = Complex(f.fromBigDecimal(a), f.zero)(f)
- def fromRational(a:Rational): Complex[A] = Complex(f.fromRational(a), f.zero)(f)
+ implicit def f:Fractional[A]
+ implicit def t:Trig[A]
+ def fromByte(a:Byte): Complex[A] = Complex(f.fromByte(a), f.zero)
+ def fromShort(a:Short): Complex[A] = Complex(f.fromShort(a), f.zero)
+ def fromInt(a:Int): Complex[A] = Complex(f.fromInt(a), f.zero)
+ def fromLong(a:Long): Complex[A] = Complex(f.fromLong(a), f.zero)
+ def fromFloat(a:Float): Complex[A] = Complex(f.fromFloat(a), f.zero)
+ def fromDouble(a:Double): Complex[A] = Complex(f.fromDouble(a), f.zero)
+ def fromBigInt(a:BigInt): Complex[A] = Complex(f.fromBigInt(a), f.zero)
+ def fromBigDecimal(a:BigDecimal): Complex[A] = Complex(f.fromBigDecimal(a), f.zero)
+ def fromRational(a:Rational): Complex[A] = Complex(f.fromRational(a), f.zero)
}
trait ConvertableToReal extends ConvertableTo[Real] {
@@ -27,7 +27,7 @@ object Numeric {
val context = ctx
}
implicit object RealIsNumeric extends RealIsNumeric
- implicit def complexIsNumeric[A:Fractional] = new ComplexIsNumeric
+ implicit def complexIsNumeric[A:Fractional:Trig] = new ComplexIsNumeric
def apply[A](implicit e:Numeric[A]):Numeric[A] = e
}
@@ -84,7 +84,7 @@ with ConvertableFromReal with ConvertableToReal with RealOrder with RealIsSigned
}
-class ComplexIsNumeric[A](implicit val f:Fractional[A])
+class ComplexIsNumeric[A](implicit val f:Fractional[A], val t:Trig[A])
extends ComplexIsField[A] with Numeric[Complex[A]] with ComplexEq[A]
with NRoot[Complex[A]] with ConvertableFromComplex[A] with ConvertableToComplex[A]
with Order[Complex[A]] with ComplexIsSigned[A] {
@@ -8,6 +8,8 @@ trait Trig[@spec(Float,Double) A] {
def e:A
def pi:A
+ def exp(a:A):A
+
def sin(a:A):A
def cos(a:A):A
def tan(a:A):A

0 comments on commit 3de5072

Please sign in to comment.