Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit 8e878cb18c3dc1fd1fea3e80927e634f2bff2ae5 1 parent 7dad8cf
Erik Osheim authored
27 TODO
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
10 src/main/scala/spire/algebra/NRoot.scala
View
@@ -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)
1  src/main/scala/spire/algebra/Ring.scala
View
@@ -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))
9 src/main/scala/spire/math/Fractional.scala
View
@@ -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 {
30 src/main/scala/spire/package.scala
View
@@ -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,7 +302,16 @@ 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)
@@ -300,11 +319,6 @@ object implicits {
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)
Please sign in to comment.
Something went wrong with that request. Please try again.