Skip to content

Commit b81e1fb

Browse files
committed
Make Field inherit from DivisionRing
Addresses typelevel/algebra#246 (comment)
1 parent 048ce2e commit b81e1fb

File tree

3 files changed

+38
-29
lines changed

3 files changed

+38
-29
lines changed

algebra-core/src/main/scala/cats/algebra/ring/DivisionRing.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@ import scala.{specialized => sp}
77
trait DivisionRing[@sp(Byte, Short, Int, Long, Float, Double) A] extends Any with Ring[A] with MultiplicativeGroup[A] {
88
self =>
99

10-
def fromDouble(a: Double): A = Field.defaultFromDouble[A](a)(self, self)
10+
/**
11+
* This is implemented in terms of basic Ring ops. However, this is
12+
* probably significantly less efficient than can be done with a
13+
* specific type. So, it is recommended that this method be
14+
* overriden.
15+
*
16+
* This is possible because a Double is a rational number.
17+
*/
18+
def fromDouble(a: Double): A = DivisionRing.defaultFromDouble[A](a)(self, self)
1119

1220
}
1321

algebra-core/src/main/scala/cats/algebra/ring/Field.scala

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ package ring
44

55
import scala.{specialized => sp}
66

7-
trait Field[@sp(Int, Long, Float, Double) A] extends Any with EuclideanRing[A] with MultiplicativeCommutativeGroup[A] {
7+
trait Field[@sp(Int, Long, Float, Double) A]
8+
extends Any
9+
with EuclideanRing[A]
10+
with DivisionRing[A]
11+
with MultiplicativeCommutativeGroup[A] {
812
self =>
913

1014
// default implementations for GCD
@@ -20,16 +24,6 @@ trait Field[@sp(Int, Long, Float, Double) A] extends Any with EuclideanRing[A] w
2024
def emod(a: A, b: A): A = zero
2125
override def equotmod(a: A, b: A): (A, A) = (div(a, b), zero)
2226

23-
/**
24-
* This is implemented in terms of basic Field ops. However, this is
25-
* probably significantly less efficient than can be done with a
26-
* specific type. So, it is recommended that this method be
27-
* overriden.
28-
*
29-
* This is possible because a Double is a rational number.
30-
*/
31-
def fromDouble(a: Double): A = Field.defaultFromDouble(a)(self, self)
32-
3327
}
3428

3529
trait FieldFunctions[F[T] <: Field[T]] extends EuclideanRingFunctions[F] with MultiplicativeGroupFunctions[F] {

algebra-laws/shared/src/main/scala/cats/algebra/laws/RingLaws.scala

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,29 @@ trait RingLaws[A] extends GroupLaws[A] { self =>
257257
}
258258
)
259259

260+
def divisionRing(implicit A: DivisionRing[A]) = new RingProperties(
261+
name = "division ring",
262+
al = additiveCommutativeGroup,
263+
ml = multiplicativeGroup,
264+
parents = Seq(ring),
265+
"fromDouble" -> forAll { (n: Double) =>
266+
if (Platform.isJvm) {
267+
// TODO: BigDecimal(n) is busted in scalajs, so we skip this test.
268+
val bd = new java.math.BigDecimal(n)
269+
val unscaledValue = new BigInt(bd.unscaledValue)
270+
val expected =
271+
if (bd.scale > 0) {
272+
A.div(A.fromBigInt(unscaledValue), A.fromBigInt(BigInt(10).pow(bd.scale)))
273+
} else {
274+
A.fromBigInt(unscaledValue * BigInt(10).pow(-bd.scale))
275+
}
276+
DivisionRing.fromDouble[A](n) ?== expected
277+
} else {
278+
Prop(true)
279+
}
280+
}
281+
)
282+
260283
// boolean rings
261284

262285
def boolRng(implicit A: BoolRng[A]) = RingProperties.fromParent(
@@ -286,23 +309,7 @@ trait RingLaws[A] extends GroupLaws[A] { self =>
286309
name = "field",
287310
al = additiveCommutativeGroup,
288311
ml = multiplicativeCommutativeGroup,
289-
parents = Seq(euclideanRing),
290-
"fromDouble" -> forAll { (n: Double) =>
291-
if (Platform.isJvm) {
292-
// TODO: BigDecimal(n) is busted in scalajs, so we skip this test.
293-
val bd = new java.math.BigDecimal(n)
294-
val unscaledValue = new BigInt(bd.unscaledValue)
295-
val expected =
296-
if (bd.scale > 0) {
297-
A.div(A.fromBigInt(unscaledValue), A.fromBigInt(BigInt(10).pow(bd.scale)))
298-
} else {
299-
A.fromBigInt(unscaledValue * BigInt(10).pow(-bd.scale))
300-
}
301-
Field.fromDouble[A](n) ?== expected
302-
} else {
303-
Prop(true)
304-
}
305-
}
312+
parents = Seq(euclideanRing, divisionRing)
306313
)
307314

308315
// Approximate fields such a Float or Double, even through filtered using FPFilter, do not work well with

0 commit comments

Comments
 (0)