Skip to content

Commit

Permalink
Make Field inherit from DivisionRing
Browse files Browse the repository at this point in the history
  • Loading branch information
armanbilge committed May 29, 2021
1 parent 048ce2e commit b81e1fb
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)

}

Expand Down
16 changes: 5 additions & 11 deletions algebra-core/src/main/scala/cats/algebra/ring/Field.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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] {
Expand Down
41 changes: 24 additions & 17 deletions algebra-laws/shared/src/main/scala/cats/algebra/laws/RingLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b81e1fb

Please sign in to comment.