Permalink
Browse files

Start to rationalize support for Fractional[A].

This commit fixes some ambiguous implicit problems with Fractional[A].
The Integral/Fractional/Numeric type classes haven't seen so much
attention and need a bit more love.

This commit adds support for literal Doubles when working with Fractional
(analogous to the support for literal Int with Rings). Arguably we should
move this to Field instead, but it works for now.

The reason it might make sense to move to Field is that this commit still
doesn't support using literal doubles with Numeric[A].
  • Loading branch information...
1 parent 7dad8cf commit 8e878cb18c3dc1fd1fea3e80927e634f2bff2ae5 @non committed Jan 4, 2013
View
@@ -1,16 +1,13 @@
1. Profiling!
-2. Test!
-3. Unify package and Rational versions of integral nroot/pow
-4. Implement nroot/pow for BigInt/BigDecimal
-5. Add sqrt/nroot/pow to Numeric, etc.
-6. Avoid overflowing BigDecimal => Double (e.g. in Complex)
-7. Create our own, better, Decimal class, with more methods
-8. Add implicits to put numerics.math.* functionality onto types
-9. Match up concrete and generic APIs
-10. Get compiler plugin for inlining implicits/ops working
-11. Unify operators (e.g. /~, %, /%, **, ~^, etc).
-
-=======
-
-1. type class standardization plus guidelines
-2.
+2. Testing!
+3. Make sure Numeric[A] is a superset of other type classes
+4. Make sure Number contains functionality for all types
+5. Add support for Rational and Complex to Number
+6. Improve macro support so we don't need operator -> methodname mapping
+7. Create our own BigFloat/Decimal class(es)
+8. Match up concrete and generic APIs
+9. Unify operators (e.g. /~, %, /%, **, etc).
+10. Make sure situations with implicits is coherent
+11. Make sure Rig/Ring/AdditiveGroup/MultiplicativeMonoid are all sane/OK
+12. Make sure specialization is consistent
+13. More benchmarks
@@ -7,6 +7,9 @@ import scala.{specialized => spec, math => mth}
import java.math.MathContext
import java.lang.Math
+// NOTE: fpow vs pow is a bit of a trainwreck :P
+// overloading is evil, but it's definitely what users will expect.
+
/**
* This is a type class for types with n-roots. The value returned by `nroot`
* and `sqrt` are only guaranteed to be approximate answers (except in the case
@@ -25,11 +28,15 @@ trait NRoot[@spec(Double,Float,Int,Long) A] {
def fpow(a:A, b:A): A
}
-final class NRootOps[A](lhs: A)(implicit n: NRoot[A]) {
+final class NRootOps[A](lhs: A)(implicit ev: NRoot[A]) {
def nroot(rhs: Int): A = macro Ops.binop[Int, A]
def sqrt(): A = macro Ops.unop[A]
def log(): A = macro Ops.unop[A]
def fpow(rhs: A): A = macro Ops.binop[A, A]
+
+ // TODO: should be macros
+ def pow(rhs: Double)(implicit c: ConvertableTo[A]) = ev.fpow(lhs, c.fromDouble(rhs))
+ def **(rhs: Double)(implicit c: ConvertableTo[A]) = ev.fpow(lhs, c.fromDouble(rhs))
}
trait DoubleIsNRoot extends NRoot[Double] {
@@ -46,7 +53,6 @@ trait FloatIsNRoot extends NRoot[Float] {
def fpow(a: Float, b: Float) = Math.pow(a, b).toFloat
}
-
trait RationalIsNRoot extends NRoot[Rational] {
implicit def context:ApproximationContext[Rational]
def nroot(a: Rational, k: Int): Rational = a.nroot(k)
@@ -30,6 +30,7 @@ trait Ring[@spec(Int,Long,Float,Double) A] extends Rig[A] with AdditiveAbGroup[A
}
final class RingOps[A](lhs:A)(implicit ev:Ring[A]) {
+ // TODO: these should really be macro-ized somehow
def -(rhs:Int): A = ev.minus(lhs, ev.fromInt(rhs))
def +(rhs:Int): A = ev.plus(lhs, ev.fromInt(rhs))
def *(rhs:Int): A = ev.times(lhs, ev.fromInt(rhs))
@@ -16,6 +16,15 @@ class FractionalOps[A](lhs:A)(implicit ev:Fractional[A]) {
def ceil() = macro Ops.unop[A]
def floor() = macro Ops.unop[A]
def round() = macro Ops.unop[A]
+
+ // TODO: these should really be macro-ized somehow
+ def +(rhs: Double): A = ev.plus(lhs, ev.fromDouble(rhs))
+ def -(rhs: Double): A = ev.minus(lhs, ev.fromDouble(rhs))
+ def *(rhs: Double): A = ev.times(lhs, ev.fromDouble(rhs))
+ def /(rhs: Double): A = ev.div(lhs, ev.fromDouble(rhs))
+ def /~(rhs: Double): A = ev.quot(lhs, ev.fromDouble(rhs))
+ def %(rhs: Double): A = ev.mod(lhs, ev.fromDouble(rhs))
+ def /%(rhs: Double): (A, A) = ev.quotmod(lhs, ev.fromDouble(rhs))
}
object Fractional {
@@ -72,8 +72,8 @@ final class LiteralIntOps(val lhs:Int) extends AnyVal {
}
final class LiteralDoubleOps(val lhs:Double) extends AnyVal {
- def pow(rhs:Int) = Ring[Double].pow(lhs, rhs)
- def **(rhs:Int) = Ring[Double].pow(lhs, rhs)
+ def pow(rhs:Double) = spire.math.pow(lhs, rhs)
+ def **(rhs:Double) = spire.math.pow(lhs, rhs)
@inline private final def c[A:Fractional:ConvertableTo:Trig]:Complex[A] =
Complex(ConvertableFrom[Double].toType[A](lhs), Fractional[A].zero)
@@ -87,6 +87,16 @@ final class LiteralDoubleOps(val lhs:Double) extends AnyVal {
def /%[A:Fractional:Trig](rhs:Complex[A]) = c /% rhs
def pow[A:Fractional:Trig](rhs:Complex[A]) = c pow rhs
def **[A:Fractional:Trig](rhs:Complex[A]) = c ** rhs
+
+ def +[A](rhs:A)(implicit ev: Fractional[A]) = ev.plus(ev.fromDouble(lhs), rhs)
+ def *[A](rhs:A)(implicit ev: Fractional[A]) = ev.times(ev.fromDouble(lhs), rhs)
+ def -[A](rhs:A)(implicit ev: Fractional[A]) = ev.minus(ev.fromDouble(lhs), rhs)
+ def /[A](rhs:A)(implicit ev: Fractional[A]) = ev.div(ev.fromDouble(lhs), rhs)
+ def /~[A](rhs:A)(implicit ev: Fractional[A]) = ev.quot(ev.fromDouble(lhs), rhs)
+ def %[A](rhs:A)(implicit ev: Fractional[A]) = ev.mod(ev.fromDouble(lhs), rhs)
+ def /%[A](rhs:A)(implicit ev: Fractional[A]) = ev.quotmod(ev.fromDouble(lhs), rhs)
+ def pow[A](rhs:A)(implicit ev: Fractional[A]) = ev.fpow(ev.fromDouble(lhs), rhs)
+ def **[A](rhs:A)(implicit ev: Fractional[A]) = ev.fpow(ev.fromDouble(lhs), rhs)
}
final class ArrayOps[@spec A](arr:Array[A]) {
@@ -292,19 +302,23 @@ final class ConversionOps[A](a: A) {
macro Ops.flip[WideningConversion[A, B], B]
}
-object implicits {
+trait LowViz {
+ // these are lower priority to prevent conflicts around operators overloaded
+ // to deal with literals
+ implicit def additiveMonoidOps[A:AdditiveMonoid](a:A) = new AdditiveMonoidOps(a)
+ implicit def additiveGroupOps[A:AdditiveGroup](a:A) = new AdditiveGroupOps(a)
+ implicit def multiplicativeSemigroupOps[A:MultiplicativeSemigroup](a:A) = new MultiplicativeSemigroupOps(a)
+ implicit def multiplicativeGroupOps[A:MultiplicativeGroup](a:A) = new MultiplicativeGroupOps(a)
+}
+
+object implicits extends LowViz {
implicit def eqOps[A:Eq](a:A) = new EqOps(a)
implicit def orderOps[A:Order](a:A) = new OrderOps(a)
implicit def semigroupOps[A:Semigroup](a:A) = new SemigroupOps(a)
implicit def groupOps[A:Group](a:A) = new GroupOps(a)
implicit def convertableOps[A:ConvertableFrom](a:A) = new ConvertableFromOps(a)
- implicit def additiveMonoidOps[A:AdditiveMonoid](a:A) = new AdditiveMonoidOps(a)
- implicit def additiveGroupOps[A:AdditiveGroup](a:A) = new AdditiveGroupOps(a)
- implicit def multiplicativeSemigroupOps[A:MultiplicativeSemigroup](a:A) = new MultiplicativeSemigroupOps(a)
- implicit def multiplicativeGroupOps[A:MultiplicativeGroup](a:A) = new MultiplicativeGroupOps(a)
-
implicit def rigOps[A:Rig](a:A) = new RigOps(a)
implicit def ringOps[A:Ring](a:A) = new RingOps(a)
implicit def euclideanRingOps[A:EuclideanRing](a:A) = new EuclideanRingOps(a)

0 comments on commit 8e878cb

Please sign in to comment.