diff --git a/algebra-core/src/main/scala/cats/algebra/ring/DivisionRing.scala b/algebra-core/src/main/scala/cats/algebra/ring/DivisionRing.scala index bf01a58379..f7dc964f28 100644 --- a/algebra-core/src/main/scala/cats/algebra/ring/DivisionRing.scala +++ b/algebra-core/src/main/scala/cats/algebra/ring/DivisionRing.scala @@ -7,7 +7,15 @@ import scala.{specialized => sp} trait DivisionRing[@sp(Byte, Short, Int, Long, Float, Double) A] extends Any with Ring[A] with MultiplicativeGroup[A] { self => - def fromDouble(a: Double): A = Field.defaultFromDouble[A](a)(self, self) + /** + * This is implemented in terms of basic Ring ops. However, this is + * probably significantly less efficient than can be done with a + * specific type. So, it is recommended that this method be + * overriden. + * + * This is possible because a Double is a rational number. + */ + def fromDouble(a: Double): A = DivisionRing.defaultFromDouble[A](a)(self, self) } diff --git a/algebra-core/src/main/scala/cats/algebra/ring/Field.scala b/algebra-core/src/main/scala/cats/algebra/ring/Field.scala index 6c5c9ea1f0..aac3faf1cd 100644 --- a/algebra-core/src/main/scala/cats/algebra/ring/Field.scala +++ b/algebra-core/src/main/scala/cats/algebra/ring/Field.scala @@ -4,7 +4,11 @@ package ring import scala.{specialized => sp} -trait Field[@sp(Int, Long, Float, Double) A] extends Any with EuclideanRing[A] with MultiplicativeCommutativeGroup[A] { +trait Field[@sp(Int, Long, Float, Double) A] + extends Any + with EuclideanRing[A] + with DivisionRing[A] + with MultiplicativeCommutativeGroup[A] { self => // default implementations for GCD @@ -20,16 +24,6 @@ trait Field[@sp(Int, Long, Float, Double) A] extends Any with EuclideanRing[A] w def emod(a: A, b: A): A = zero override def equotmod(a: A, b: A): (A, A) = (div(a, b), zero) - /** - * This is implemented in terms of basic Field ops. However, this is - * probably significantly less efficient than can be done with a - * specific type. So, it is recommended that this method be - * overriden. - * - * This is possible because a Double is a rational number. - */ - def fromDouble(a: Double): A = Field.defaultFromDouble(a)(self, self) - } trait FieldFunctions[F[T] <: Field[T]] extends EuclideanRingFunctions[F] with MultiplicativeGroupFunctions[F] { diff --git a/algebra-laws/shared/src/main/scala/cats/algebra/laws/RingLaws.scala b/algebra-laws/shared/src/main/scala/cats/algebra/laws/RingLaws.scala index 6c45641c36..807c719c02 100644 --- a/algebra-laws/shared/src/main/scala/cats/algebra/laws/RingLaws.scala +++ b/algebra-laws/shared/src/main/scala/cats/algebra/laws/RingLaws.scala @@ -257,6 +257,29 @@ trait RingLaws[A] extends GroupLaws[A] { self => } ) + def divisionRing(implicit A: DivisionRing[A]) = new RingProperties( + name = "division ring", + al = additiveCommutativeGroup, + ml = multiplicativeGroup, + parents = Seq(ring), + "fromDouble" -> forAll { (n: Double) => + if (Platform.isJvm) { + // TODO: BigDecimal(n) is busted in scalajs, so we skip this test. + val bd = new java.math.BigDecimal(n) + val unscaledValue = new BigInt(bd.unscaledValue) + val expected = + if (bd.scale > 0) { + A.div(A.fromBigInt(unscaledValue), A.fromBigInt(BigInt(10).pow(bd.scale))) + } else { + A.fromBigInt(unscaledValue * BigInt(10).pow(-bd.scale)) + } + DivisionRing.fromDouble[A](n) ?== expected + } else { + Prop(true) + } + } + ) + // boolean rings def boolRng(implicit A: BoolRng[A]) = RingProperties.fromParent( @@ -286,23 +309,7 @@ trait RingLaws[A] extends GroupLaws[A] { self => name = "field", al = additiveCommutativeGroup, ml = multiplicativeCommutativeGroup, - parents = Seq(euclideanRing), - "fromDouble" -> forAll { (n: Double) => - if (Platform.isJvm) { - // TODO: BigDecimal(n) is busted in scalajs, so we skip this test. - val bd = new java.math.BigDecimal(n) - val unscaledValue = new BigInt(bd.unscaledValue) - val expected = - if (bd.scale > 0) { - A.div(A.fromBigInt(unscaledValue), A.fromBigInt(BigInt(10).pow(bd.scale))) - } else { - A.fromBigInt(unscaledValue * BigInt(10).pow(-bd.scale)) - } - Field.fromDouble[A](n) ?== expected - } else { - Prop(true) - } - } + parents = Seq(euclideanRing, divisionRing) ) // Approximate fields such a Float or Double, even through filtered using FPFilter, do not work well with