├── .gitignore ├── CODE_OF_CONDUCT.md ├── COPYING ├── README.md ├── build.sbt ├── project └── build.properties └── src ├── main └── scala │ └── spire │ ├── Example.scala │ ├── algebra │ ├── CRig.scala │ ├── CRing.scala │ ├── Eq.scala │ ├── Field.scala │ ├── Order.scala │ └── PartialOrder.scala │ ├── instances.scala │ ├── math │ ├── Complex.scala │ ├── FastComplex.scala │ ├── Rat.scala │ ├── Sorting.scala │ ├── UInt.scala │ └── ULong.scala │ ├── std │ ├── any.scala │ ├── bigDecimal.scala │ ├── bigInteger.scala │ ├── double.scala │ ├── float.scala │ ├── int.scala │ ├── long.scala │ └── package.scala │ └── syntax │ ├── Literals.scala │ ├── Syntax.scala │ ├── macros │ ├── cforMacros.scala │ └── genericLiteralMacros.scala │ ├── package.scala │ └── primitives.scala └── test └── scala └── spire ├── CforReturn.scala ├── CforSpec.scala └── GenericLiterals.scala /.gitignore: -------------------------------------------------------------------------------- 1 | dumps 2 | 3 | *.log 4 | *.o 5 | *.out 6 | src_managed 7 | *.sc 8 | 9 | *.DS_Store 10 | *.class 11 | *.tasty 12 | *.hasTasty 13 | *.log 14 | *.swp 15 | *~ 16 | tags 17 | 18 | dist/* 19 | target/ 20 | lib_managed/ 21 | src_managed/ 22 | project/boot/ 23 | project/plugins/project/ 24 | project/local-plugins.sbt 25 | .history 26 | .ensime 27 | .ensime_cache/ 28 | .sbt-scripted/ 29 | local.sbt 30 | 31 | .vscode/ 32 | 33 | # Dotty IDE 34 | .dotty-ide-dev-port 35 | .dotty-ide-artifact 36 | .dotty-ide.json 37 | 38 | # idea 39 | .idea 40 | .idea_modules 41 | /.worksheet/ 42 | 43 | # Ignore output files but keep the directory 44 | out/ 45 | build/ 46 | !out/.keep 47 | testlogs/ 48 | 49 | # Ignore build-file 50 | .packages 51 | /.cache-main 52 | /.cache-tests 53 | 54 | 55 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | People are expected to follow the [Scala Code of Conduct](https://www.scala-lang.org/conduct/) 2 | when discussing Spire on the Github page, in Gitter, the IRC channel, 3 | mailing list, and other official venues. 4 | 5 | Concerns or issues can be sent to any of Spire's maintainers, or to the 6 | [Typelevel](http://typelevel.org/about.html) organization. 7 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2019 Erik Osheim, Tom Switzer, Denis Rosset 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spire-scala3 2 | Bringing Spire to Dotty/Scala 3, derived from `denisrosset/minispire` 3 | 4 | 13/10/2019 5 | - Addition of generic number literals for types with `CRing` and `Field` given instances. 6 | - default methods to make values with a `Field`: `fromDouble` and `fromBigDecimal`. 7 | 8 | 25/06/2019 9 | - Reimplement all `cfor` macros, with added support for `NumericRange[Long]`. 10 | 11 | 11/06/2019 12 | - Removal of macros and using inlined extension methods. 13 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | val dottyVersion = "3.3.2" 2 | // val dottyVersion = dottyLatestNightlyBuild.get 3 | val spireScala3Version = "0.1.0-SNAPSHOT" 4 | 5 | lazy val root = project 6 | .in(file(".")) 7 | .settings( 8 | name := "spire-scala3", 9 | version := spireScala3Version, 10 | 11 | scalaVersion := dottyVersion, 12 | scalacOptions += "-Yexplicit-nulls", 13 | 14 | libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test", 15 | libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.17.0" % Test 16 | ) 17 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.7 2 | -------------------------------------------------------------------------------- /src/main/scala/spire/Example.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | 3 | import spire.algebra.Order 4 | import spire.instances.{given Order[Int]} 5 | 6 | object Example extends App { 7 | val array = Array(2, 3, 1, 4) 8 | spire.math.Sorting.sort(array) 9 | println(array.mkString("(",",",")")) 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/spire/algebra/CRig.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package algebra 3 | 4 | import scala.{specialized => sp} 5 | import scala.annotation.tailrec 6 | 7 | /** 8 | * Typeclass for number types that implement addition and multiplication, with the 9 | * availability of values that behave like zero and one. 10 | */ 11 | trait CRig[@sp(Int, Long, Float, Double) A] { 12 | 13 | // Abstract members to implement 14 | 15 | def plus(x: A, y: A): A 16 | 17 | def times(x: A, y: A): A 18 | 19 | def zero: A 20 | 21 | def one: A 22 | 23 | /** 24 | * Tests if `a` is zero. 25 | */ 26 | def isZero(a: A)(using ev: Eq[A]): Boolean = ev.eqv(a, zero) 27 | 28 | /** 29 | * Tests if `a` is one. 30 | */ 31 | def isOne(a: A)(using ev: Eq[A]): Boolean = ev.eqv(a, one) 32 | 33 | // Additional methods 34 | 35 | def sumN(a: A, n: Int): A = 36 | if (n > 0) positiveSumN(a, n) 37 | else if (n == 0) zero 38 | else throw new IllegalArgumentException(s"Illegal negative exponent to sumN: $n") 39 | 40 | protected[this] def positiveSumN(a: A, n: Int): A = { 41 | @tailrec def loop(b: A, k: Int, extra: A): A = 42 | if (k == 1) plus(b, extra) else { 43 | val x = if ((k & 1) == 1) plus(b, extra) else extra 44 | loop(plus(b, b), k >>> 1, x) 45 | } 46 | if (n == 1) a else loop(a, n - 1, a) 47 | } 48 | 49 | } 50 | 51 | trait CRigFunctions[C[T] <: CRig[T]] { 52 | 53 | def plus[@sp(Int, Long, Float, Double) A](x: A, y: A)(using ev: C[A]): A = 54 | ev.plus(x, y) 55 | 56 | def times[@sp(Int, Long, Float, Double) A](x: A, y: A)(using ev: C[A]): A = 57 | ev.times(x, y) 58 | 59 | def zero[@sp(Int, Long, Float, Double) A](using ev: C[A]): A = 60 | ev.zero 61 | 62 | def one[@sp(Int, Long, Float, Double) A](using ev: C[A]): A = 63 | ev.one 64 | 65 | def isZero[@sp(Int, Long, Float, Double) A](a: A)(using ev0: C[A], ev1: Eq[A]): Boolean = 66 | ev0.isZero(a) 67 | 68 | def isOne[@sp(Int, Long, Float, Double) A](a: A)(using ev0: C[A], ev1: Eq[A]): Boolean = 69 | ev0.isOne(a) 70 | 71 | def sumN[@sp(Int, Long, Float, Double) A](a: A, n: Int)(using ev: C[A]): A = 72 | ev.sumN(a, n) 73 | 74 | } 75 | 76 | object CRig extends CRigFunctions[CRig] { 77 | inline def apply[A](using CRig[A]) = summon[CRig[A]] 78 | } 79 | -------------------------------------------------------------------------------- /src/main/scala/spire/algebra/CRing.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package algebra 3 | 4 | import scala.annotation.tailrec 5 | import scala.{specialized => sp} 6 | 7 | /** 8 | * Typeclass for number types that implement addition, subtraction and multiplication, with the 9 | * availability of values that behave like zero and one. 10 | */ 11 | trait CRing[@sp(Int, Long, Float, Double) A] extends CRig[A] { 12 | 13 | def negate(x: A): A 14 | 15 | def minus(x: A, y: A): A = plus(x, negate(y)) 16 | 17 | override def sumN(a: A, n: Int): A = 18 | if (n > 0) positiveSumN(a, n) 19 | else if (n == 0) zero 20 | else if (n == Int.MinValue) positiveSumN(negate(plus(a, a)), 1073741824) 21 | else positiveSumN(negate(a), -n) 22 | 23 | /** 24 | * Convert the given integer to an instance of A. 25 | * 26 | * Defined to be equivalent to `sumN(one, n)`. 27 | * 28 | * That is, `n` repeated summations of this ring's `one`, or `-n` 29 | * summations of `-one` if `n` is negative. 30 | * 31 | * Most type class instances should consider overriding this method 32 | * for performance reasons. 33 | */ 34 | def fromInt(n: Int): A = sumN(one, n) 35 | 36 | /** 37 | * Convert the given BigInt to an instance of A. 38 | * 39 | * This is equivalent to `n` repeated summations of this ring's `one`, or 40 | * `-n` summations of `-one` if `n` is negative. 41 | * 42 | * Most type class instances should consider overriding this method for 43 | * performance reasons. 44 | */ 45 | def fromBigInt(n: BigInt): A = 46 | if (n.isValidInt) { 47 | fromInt(n.toInt) 48 | } else { 49 | val d = fromInt(1 << 30) 50 | val mask = (1L << 30) - 1 51 | @tailrec def loop(k: A, x: BigInt, acc: A): A = 52 | if (x.isValidInt) { 53 | plus(times(k, fromInt(x.toInt)), acc) 54 | } else { 55 | val y = x >> 30 56 | val r = fromInt((x & mask).toInt) 57 | loop(times(d, k), y, plus(times(k, r), acc)) 58 | } 59 | 60 | val absValue = loop(one, n.abs, zero) 61 | if (n.signum < 0) negate(absValue) else absValue 62 | } 63 | 64 | } 65 | 66 | trait CRingFunctions[C[T] <: CRing[T]] extends CRigFunctions[C] { 67 | 68 | def negate[@sp(Int, Long, Float, Double) A](x: A)(using ev: C[A]): A = 69 | ev.negate(x) 70 | 71 | def minus[@sp(Int, Long, Float, Double) A](x: A, y: A)(using ev: C[A]): A = 72 | ev.minus(x, y) 73 | 74 | def fromInt[@sp(Int, Long, Float, Double) A](n: Int)(using ev: C[A]): A = 75 | ev.fromInt(n) 76 | 77 | def fromBigInt[@sp(Int, Long, Float, Double) A](n: BigInt)(using ev: C[A]): A = 78 | ev.fromBigInt(n) 79 | 80 | } 81 | 82 | object CRing extends CRingFunctions[CRing] { 83 | inline def apply[A](using CRing[A]) = summon[CRing[A]] 84 | } 85 | -------------------------------------------------------------------------------- /src/main/scala/spire/algebra/Eq.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package algebra 3 | 4 | import scala.{specialized => sp} 5 | 6 | /** 7 | * A type class used to determine equality between 2 instances of the same 8 | * type. Any 2 instances `x` and `y` are equal if `eqv(x, y)` is `true`. 9 | * Moreover, `eqv` should form an equivalence relation. 10 | */ 11 | trait Eq[@sp A] { self => 12 | 13 | /** 14 | * Returns `true` if `x` and `y` are equivalent, `false` otherwise. 15 | */ 16 | def eqv(x: A, y: A): Boolean 17 | 18 | /** 19 | * Returns `false` if `x` and `y` are equivalent, `true` otherwise. 20 | */ 21 | def neqv(x: A, y: A): Boolean = !eqv(x, y) 22 | } 23 | 24 | abstract class EqFunctions[E[T] <: Eq[T]] { 25 | 26 | def eqv[@sp A](x: A, y: A)(using ev: E[A]): Boolean = 27 | ev.eqv(x, y) 28 | 29 | def neqv[@sp A](x: A, y: A)(using ev: E[A]): Boolean = 30 | ev.neqv(x, y) 31 | 32 | } 33 | 34 | object Eq extends EqFunctions[Eq] { 35 | 36 | /** 37 | * Access a given `Eq[A]`. 38 | */ 39 | inline def apply[A](using Eq[A]) = summon[Eq[A]] 40 | 41 | /** 42 | * Convert a given `Eq[B]` to an `Eq[A]` using the given 43 | * function `f`. 44 | */ 45 | def by[@sp A, @sp B](f: A => B)(using ev: Eq[B]): Eq[A] = 46 | new Eq[A] { 47 | def eqv(x: A, y: A) = ev.eqv(f(x), f(y)) 48 | } 49 | 50 | /** 51 | * Create an `Eq` instance from an `eqv` implementation. 52 | */ 53 | def instance[A](f: (A, A) => Boolean): Eq[A] = 54 | new Eq[A] { 55 | def eqv(x: A, y: A) = f(x, y) 56 | } 57 | 58 | /** 59 | * An `Eq[A]` that delegates to universal equality (`==`). 60 | * 61 | * This can be useful for case classes, which have reasonable `equals` 62 | * implementations 63 | */ 64 | def fromUniversalEquals[A]: Eq[A] = 65 | new Eq[A] { 66 | def eqv(x: A, y: A) = x == y 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/scala/spire/algebra/Field.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package algebra 3 | 4 | import scala.{ specialized => sp } 5 | import java.math.BigDecimal.{valueOf => JBigDecimal} 6 | 7 | trait Field[@sp(Int, Long, Float, Double) A] extends CRing[A] { self => 8 | 9 | // To implement 10 | 11 | def div(x: A, y: A): A 12 | 13 | // Methods 14 | 15 | def reciprocal(x: A): A = div(one, x) 16 | 17 | def fromDouble(n: Double): A = 18 | if n.isWhole then 19 | if n.isValidInt then 20 | fromInt(n.toInt) 21 | else 22 | fromBigInt(JBigDecimal(n).nn.toBigInteger.nn) 23 | else 24 | fromBigDecimal(BigDecimal(n)) 25 | 26 | def fromBigDecimal(n: BigDecimal): A = 27 | val quot = fromBigInt(n.quot(Field.one).toBigInt) 28 | if n.isWhole then 29 | quot 30 | else 31 | val remRaw = n.remainder(Field.one) 32 | val unscaled = fromBigInt(remRaw.underlying.unscaledValue.nn) 33 | val scalePow = fromBigInt(JBigDecimal(scala.math.pow(10.0, remRaw.scale.toDouble)).nn.toBigInteger.nn) 34 | plus(quot, div(unscaled, scalePow)) 35 | 36 | } 37 | 38 | trait FieldFunctions[F[T] <: Field[T]] extends CRingFunctions[F] { 39 | 40 | def reciprocal[@sp(Int, Long, Float, Double) A](x: A)(using ev: F[A]): A = 41 | ev.reciprocal(x) 42 | 43 | def div[@sp(Int, Long, Float, Double) A](x: A, y: A)(using ev: F[A]): A = 44 | ev.div(x, y) 45 | 46 | } 47 | 48 | object Field extends FieldFunctions[Field] { 49 | private val one: BigDecimal = 1 50 | inline def apply[A](using Field[A]) = summon[Field[A]] 51 | } 52 | -------------------------------------------------------------------------------- /src/main/scala/spire/algebra/Order.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package algebra 3 | 4 | import scala.{specialized => sp} 5 | 6 | /** 7 | * The `Order` type class is used to define a total ordering on some type `A`. 8 | * An order is defined by a relation <=, which obeys the following laws: 9 | * 10 | * - either x <= y or y <= x (totality) 11 | * - if x <= y and y <= x, then x == y (antisymmetry) 12 | * - if x <= y and y <= z, then x <= z (transitivity) 13 | * 14 | * The truth table for compare is defined as follows: 15 | * 16 | * x <= y x >= y Int 17 | * true true = 0 (corresponds to x == y) 18 | * true false < 0 (corresponds to x < y) 19 | * false true > 0 (corresponds to x > y) 20 | * 21 | * By the totality law, x <= y and y <= x cannot be both false. 22 | */ 23 | trait Order[@sp A] extends PartialOrder[A] { self => 24 | 25 | /** 26 | * Result of comparing `x` with `y`. Returns an Int whose sign is: 27 | * - negative iff `x < y` 28 | * - zero iff `x = y` 29 | * - positive iff `x > y` 30 | */ 31 | def compare(x: A, y: A): Int 32 | 33 | def partialCompare(x: A, y: A): Double = compare(x, y).toDouble 34 | 35 | // The following may be overridden for performance: 36 | 37 | /** 38 | * Returns true if `x` = `y`, false otherwise. 39 | */ 40 | override def eqv(x: A, y: A): Boolean = 41 | compare(x, y) == 0 42 | 43 | /** 44 | * Returns true if `x` != `y`, false otherwise. 45 | * 46 | * Note: this default implementation provided by [[Order]] is the same as the 47 | * one defined in [[Eq]], but for purposes of binary compatibility, the 48 | * override in [[Order]] has not yet been removed. 49 | * See [[https://github.com/typelevel/cats/pull/2230#issuecomment-381818633 this discussion]]. 50 | */ 51 | override def neqv(x: A, y: A): Boolean = !eqv(x, y) 52 | 53 | /** 54 | * Returns true if `x` <= `y`, false otherwise. 55 | */ 56 | override def lteqv(x: A, y: A): Boolean = 57 | compare(x, y) <= 0 58 | 59 | /** 60 | * Returns true if `x` < `y`, false otherwise. 61 | */ 62 | override def lt(x: A, y: A): Boolean = 63 | compare(x, y) < 0 64 | 65 | /** 66 | * Returns true if `x` >= `y`, false otherwise. 67 | */ 68 | override def gteqv(x: A, y: A): Boolean = 69 | compare(x, y) >= 0 70 | 71 | /** 72 | * Returns true if `x` > `y`, false otherwise. 73 | */ 74 | override def gt(x: A, y: A): Boolean = 75 | compare(x, y) > 0 76 | } 77 | 78 | abstract class OrderFunctions[O[T] <: Order[T]] extends PartialOrderFunctions[O] { 79 | 80 | def compare[@sp A](x: A, y: A)(using ev: O[A]): Int = 81 | ev.compare(x, y) 82 | 83 | } 84 | 85 | object Order extends OrderFunctions[Order] { 86 | 87 | /** 88 | * Access a given `Order[A]`. 89 | */ 90 | inline def apply[A](using Order[A]) = summon[Order[A]] 91 | 92 | /** 93 | * Convert a given `Order[B]` to an `Order[A]` using the given 94 | * function `f`. 95 | */ 96 | def by[@sp A, @sp B](f: A => B)(using ev: Order[B]): Order[A] = 97 | new Order[A] { 98 | def compare(x: A, y: A): Int = ev.compare(f(x), f(y)) 99 | } 100 | 101 | /** 102 | * Define an `Order[A]` using the given function `f`. 103 | */ 104 | def from[@sp A](f: (A, A) => Int): Order[A] = 105 | new Order[A] { 106 | def compare(x: A, y: A) = f(x, y) 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/scala/spire/algebra/PartialOrder.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package algebra 3 | 4 | import java.lang.Double.isNaN 5 | import scala.{specialized => sp} 6 | 7 | /** 8 | * The `PartialOrder` type class is used to define a partial ordering on some type `A`. 9 | * 10 | * A partial order is defined by a relation <=, which obeys the following laws: 11 | * 12 | * - x <= x (reflexivity) 13 | * - if x <= y and y <= x, then x = y (anti-symmetry) 14 | * - if x <= y and y <= z, then x <= z (transitivity) 15 | * 16 | * To compute both <= and >= at the same time, we use a Double number 17 | * to encode the result of the comparisons x <= y and x >= y. 18 | * The truth table is defined as follows: 19 | * 20 | * x <= y x >= y Double 21 | * true true = 0.0 (corresponds to x = y) 22 | * false false = NaN (x and y cannot be compared) 23 | * true false = -1.0 (corresponds to x < y) 24 | * false true = 1.0 (corresponds to x > y) 25 | */ 26 | trait PartialOrder[@sp A] extends Eq[A] { self => 27 | 28 | /** 29 | * Result of comparing `x` with `y`. Returns NaN if operands are not 30 | * comparable. If operands are comparable, returns a Double whose 31 | * sign is: 32 | * - negative iff `x < y` 33 | * - zero iff `x = y` 34 | * - positive iff `x > y` 35 | */ 36 | def partialCompare(x: A, y: A): Double 37 | 38 | /** 39 | * Result of comparing `x` with `y`. Returns None if operands are 40 | * not comparable. If operands are comparable, returns Some[Int] 41 | * where the Int sign is: 42 | * - negative iff `x < y` 43 | * - zero iff `x = y` 44 | * - positive iff `x > y` 45 | */ 46 | def tryCompare(x: A, y: A): Option[Int] = { 47 | val c = partialCompare(x, y) 48 | if (isNaN(c)) None else Some(c.sign.toInt) 49 | } 50 | 51 | // The following may be overridden for performance: 52 | 53 | /** 54 | * Returns true if `x` = `y`, false otherwise. 55 | */ 56 | def eqv(x: A, y: A): Boolean = partialCompare(x, y) == 0 57 | 58 | /** 59 | * Returns true if `x` <= `y`, false otherwise. 60 | */ 61 | def lteqv(x: A, y: A): Boolean = partialCompare(x, y) <= 0 62 | 63 | /** 64 | * Returns true if `x` < `y`, false otherwise. 65 | */ 66 | def lt(x: A, y: A): Boolean = partialCompare(x, y) < 0 67 | 68 | /** 69 | * Returns true if `x` >= `y`, false otherwise. 70 | */ 71 | def gteqv(x: A, y: A): Boolean = partialCompare(x, y) >= 0 72 | 73 | /** 74 | * Returns true if `x` > `y`, false otherwise. 75 | */ 76 | def gt(x: A, y: A): Boolean = partialCompare(x, y) > 0 77 | } 78 | 79 | abstract class PartialOrderFunctions[P[T] <: PartialOrder[T]] extends EqFunctions[P] { 80 | 81 | def partialCompare[@sp A](x: A, y: A)(using ev: P[A]): Double = 82 | ev.partialCompare(x, y) 83 | def tryCompare[@sp A](x: A, y: A)(using ev: P[A]): Option[Int] = 84 | ev.tryCompare(x, y) 85 | 86 | def lteqv[@sp A](x: A, y: A)(using ev: P[A]): Boolean = 87 | ev.lteqv(x, y) 88 | def lt[@sp A](x: A, y: A)(using ev: P[A]): Boolean = 89 | ev.lt(x, y) 90 | def gteqv[@sp A](x: A, y: A)(using ev: P[A]): Boolean = 91 | ev.gteqv(x, y) 92 | def gt[@sp A](x: A, y: A)(using ev: P[A]): Boolean = 93 | ev.gt(x, y) 94 | 95 | } 96 | 97 | object PartialOrder extends PartialOrderFunctions[PartialOrder] { 98 | 99 | /** 100 | * Access a given `PartialOrder[A]`. 101 | */ 102 | inline def apply[A](using PartialOrder[A]) = summon[PartialOrder[A]] 103 | 104 | /** 105 | * Convert a given `PartialOrder[B]` to an `PartialOrder[A]` using the given 106 | * function `f`. 107 | */ 108 | def by[@sp A, @sp B](f: A => B)(using ev: PartialOrder[B]): PartialOrder[A] = 109 | new PartialOrder[A] { 110 | def partialCompare(x: A, y: A): Double = ev.partialCompare(f(x), f(y)) 111 | } 112 | 113 | /** 114 | * Define a `PartialOrder[A]` using the given function `f`. 115 | */ 116 | def from[@sp A](f: (A, A) => Double): PartialOrder[A] = 117 | new PartialOrder[A] { 118 | def partialCompare(x: A, y: A) = f(x, y) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/scala/spire/instances.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | 3 | import spire.syntax.AllSyntax 4 | import spire.std.AnyInstances 5 | 6 | object instances extends AnyInstances with AllSyntax 7 | -------------------------------------------------------------------------------- /src/main/scala/spire/math/Complex.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package math 3 | 4 | import spire.algebra._ 5 | 6 | import spire.syntax.field.given 7 | import spire.syntax.order.given 8 | 9 | 10 | object Complex { 11 | 12 | def i[@specialized(Float, Double) T](using T: Field[T]): Complex[T] = 13 | new Complex(T.zero, T.one) 14 | 15 | def one[@specialized(Float, Double) T](using T: Field[T]): Complex[T] = 16 | new Complex(T.one, T.zero) 17 | 18 | def zero[@specialized(Float, Double) T](using T: Field[T]): Complex[T] = 19 | new Complex(T.zero, T.zero) 20 | 21 | def fromInt[@specialized(Float, Double) T](n: Int)(using T: Field[T]): Complex[T] = 22 | new Complex(T.fromInt(n), T.zero) 23 | 24 | def apply[@specialized(Float, Double) T: Field](real: T): Complex[T] = 25 | new Complex(real, CRing[T].zero) 26 | 27 | given [A: Field: Order]: Field[Complex[A]] with Eq[Complex[A]] with { 28 | override def minus(a: Complex[A], b: Complex[A]): Complex[A] = a - b 29 | def negate(a: Complex[A]): Complex[A] = -a 30 | def one: Complex[A] = Complex.one 31 | def plus(a: Complex[A], b: Complex[A]): Complex[A] = a + b 32 | override def times(a: Complex[A], b: Complex[A]): Complex[A] = a * b 33 | def zero: Complex[A] = Complex.zero 34 | override def fromInt(n: Int): Complex[A] = Complex.fromInt[A](n) 35 | def div(a: Complex[A], b: Complex[A]): Complex[A] = a / b 36 | def eqv(x: Complex[A], y: Complex[A]): Boolean = x eqv y 37 | override def neqv(x: Complex[A], y: Complex[A]): Boolean = x neqv y 38 | } 39 | 40 | } 41 | 42 | /** Complex numbers. Depending on the underlying scalar T, can represent the Gaussian integers (T = BigInt/SafeLong), 43 | * the Gaussian rationals (T = Rational) or the complex number field (T: Field). 44 | * 45 | * Note that we require T to be at least CRing, a commutative ring, so the implementation below is slightly 46 | * less general than the Cayley-Dickson construction. 47 | */ 48 | final case class Complex[@specialized(Float, Double) T](real: T, imag: T) extends Serializable { lhs => 49 | 50 | def absSquare(using r: Field[T]): T = real*real + imag*imag 51 | 52 | def conjugate(using f: Field[T]): Complex[T] = new Complex(real, -imag) 53 | 54 | def asTuple: (T, T) = (real, imag) 55 | 56 | def isZero(using f: Field[T], e: Eq[T]): Boolean = real.isZero && imag.isZero 57 | def isImaginary(using f: Field[T], e: Eq[T]): Boolean = real.isZero 58 | def isReal(using f: Field[T], e: Eq[T]): Boolean = imag.isZero 59 | 60 | def eqv(b: Complex[T])(using o: Eq[T]): Boolean = real === b.real && imag === b.imag 61 | def neqv(b: Complex[T])(using o: Eq[T]): Boolean = real =!= b.real || imag =!= b.imag 62 | 63 | def unary_-(using r: Field[T]): Complex[T] = new Complex(-real, -imag) 64 | 65 | def +(rhs: T)(using r: Field[T]): Complex[T] = new Complex(real + rhs, imag) 66 | def -(rhs: T)(using r: Field[T]): Complex[T] = new Complex(real - rhs, imag) 67 | def *(rhs: T)(using r: Field[T]): Complex[T] = new Complex(real * rhs, imag * rhs) 68 | def /(rhs: T)(using r: Field[T]): Complex[T] = new Complex(real / rhs, imag / rhs) 69 | 70 | def +(b: Complex[T])(using r: Field[T]): Complex[T] = 71 | new Complex(real + b.real, imag + b.imag) 72 | 73 | def -(b: Complex[T])(using r: Field[T]): Complex[T] = 74 | new Complex(real - b.real, imag - b.imag) 75 | 76 | def *(b: Complex[T])(using r: Field[T]): Complex[T] = 77 | new Complex(real * b.real - imag * b.imag, imag * b.real + real * b.imag) 78 | 79 | def /(b: Complex[T])(using f: Field[T], o: Order[T]): Complex[T] = { 80 | val abs_breal = if (b.real < Field[T].zero) -b.real else b.real 81 | val abs_bimag = if (b.imag < Field[T].zero) -b.imag else b.imag 82 | 83 | if (abs_breal >= abs_bimag) { 84 | if (abs_breal === f.zero) throw new Exception("/ by zero") 85 | val ratio = b.imag / b.real 86 | val denom = b.real + b.imag * ratio 87 | new Complex((real + imag * ratio) / denom, (imag - real * ratio) / denom) 88 | 89 | } else { 90 | if (abs_bimag === f.zero) throw new Exception("/ by zero") 91 | val ratio = b.real / b.imag 92 | val denom = b.real * ratio + b.imag 93 | new Complex((real * ratio + imag) / denom, (imag * ratio - real) /denom) 94 | } 95 | } 96 | 97 | override def hashCode: Int = (19 * real.##) + (41 * imag.##) + 97 98 | 99 | // not typesafe, so this is the best we can do :( 100 | override def equals(that: Any): Boolean = that match { 101 | case that: Complex[_] => (this.real == that.real) && (this.imag == that.real) 102 | case _ => false 103 | } 104 | 105 | def ===(that: Complex[_]): Boolean = 106 | real == that.real && imag == that.imag 107 | 108 | def =!=(that: Complex[_]): Boolean = 109 | !(this === that) 110 | 111 | override def toString: String = s"($real + ${imag}i)" 112 | } 113 | -------------------------------------------------------------------------------- /src/main/scala/spire/math/FastComplex.scala: -------------------------------------------------------------------------------- 1 | package spire.math 2 | 3 | object FloatComplex { 4 | import FastComplex.{encode} 5 | 6 | final def apply(real: Float, imag: Float): FloatComplex = 7 | new FloatComplex(encode(real, imag)) 8 | 9 | final def apply(real: Double, imag: Double): FloatComplex = 10 | new FloatComplex(encode(real.toFloat, imag.toFloat)) 11 | 12 | final val i: FloatComplex = new FloatComplex(4575657221408423936L) 13 | final val one: FloatComplex = new FloatComplex(1065353216L) 14 | final val zero: FloatComplex = new FloatComplex(0L) 15 | } 16 | 17 | /** 18 | * Value class which encodes two floating point values in a Long. 19 | * 20 | * We get (basically) unboxed complex numbers using this hack. 21 | * The underlying implementation lives in the FastComplex object. 22 | */ 23 | class FloatComplex(val u: Long) extends AnyVal { 24 | override final def toString: String = s"($real+${imag}i)" 25 | 26 | final def real: Float = FastComplex.real(u) 27 | final def imag: Float = FastComplex.imag(u) 28 | final def repr: String = s"FloatComplex($real, $imag)" 29 | final def conjugate: FloatComplex = new FloatComplex(FastComplex.conjugate(u)) 30 | final def isWhole: Boolean = FastComplex.isWhole(u) 31 | final def signum: Int = FastComplex.signum(u) 32 | final def complexSignum: FloatComplex = new FloatComplex(FastComplex.complexSignum(u)) 33 | final def negate: FloatComplex = new FloatComplex(FastComplex.negate(u)) 34 | 35 | final def +(b: FloatComplex): FloatComplex = new FloatComplex(FastComplex.add(u, b.u)) 36 | final def -(b: FloatComplex): FloatComplex = new FloatComplex(FastComplex.subtract(u, b.u)) 37 | final def *(b: FloatComplex): FloatComplex = new FloatComplex(FastComplex.multiply(u, b.u)) 38 | final def /(b: FloatComplex): FloatComplex = new FloatComplex(FastComplex.divide(u, b.u)) 39 | } 40 | 41 | 42 | /** 43 | * FastComplex is an ugly, beautiful hack. 44 | * 45 | * The basic idea is to encode two 32-bit Floats into a single 64-bit Long. 46 | * The lower-32 bits are the "real" Float and the upper-32 are the "imaginary" 47 | * Float. 48 | * 49 | * Since we're overloading the meaning of Long, all the operations have to be 50 | * defined on the FastComplex object, meaning the syntax for using this is a 51 | * bit ugly. To add to the ugly beauty of the whole thing I could imagine 52 | * defining operators on Long like +@, -@, *@, /@, etc. 53 | * 54 | * You might wonder why it's even worth doing this. The answer is that when 55 | * you need to allocate an array of e.g. 10-20 million complex numbers, the GC 56 | * overhead of using *any* object is HUGE. Since we can't build our own 57 | * "pass-by-value" types on the JVM we are stuck doing an encoding like this. 58 | * 59 | * Here are some profiling numbers for summing an array of complex numbers, 60 | * timed against a concrete case class implementation using Float (in ms): 61 | * 62 | * size | encoded | class 63 | * 1M | 5.1 | 5.8 64 | * 5M | 28.5 | 91.7 65 | * 10M | 67.7 | 828.1 66 | * 20M | 228.0 | 2687.0 67 | * 68 | * Not bad, eh? 69 | */ 70 | object FastComplex { 71 | import java.lang.Math.{atan2, cos, sin} 72 | 73 | // note the superstitious use of inline and final everywhere 74 | 75 | final def apply(real: Float, imag: Float): Long = encode(real, imag) 76 | final def apply(real: Double, imag: Double): Long = encode(real.toFloat, imag.toFloat) 77 | 78 | // encode a float as some bits 79 | inline def bits(n: Float): Int = java.lang.Float.floatToIntBits(n) 80 | 81 | // decode some bits into a float 82 | inline def bits(n: Int): Float = java.lang.Float.intBitsToFloat(n) 83 | 84 | // get the real part of the complex number 85 | inline def real(d: Long): Float = bits((d & 0xffffffff).toInt) 86 | 87 | // get the imaginary part of the complex number 88 | inline def imag(d: Long): Float = bits((d >>> 32).toInt) 89 | 90 | // define some handy constants 91 | final val i: Long = encode(0.0F, 1.0F) 92 | final val one: Long = encode(1.0F, 0.0F) 93 | final val zero: Long = encode(0.0F, 0.0F) 94 | 95 | // encode two floats representing a complex number 96 | inline def encode(real: Float, imag: Float): Long = 97 | (bits(real) & 0xffffffffL) | ((bits(imag) & 0xffffffffL) << 32) 98 | 99 | // decode should be avoided in fast code because it allocates a Tuple2. 100 | final def decode(d: Long): (Float, Float) = (real(d), imag(d)) 101 | 102 | // produces a string representation of the Long/(Float,Float) 103 | final def toRepr(d: Long): String = s"FastComplex($d -> ${decode(d)})" 104 | 105 | // get the complex conjugate 106 | final def conjugate(d: Long): Long = encode(real(d), -imag(d)) 107 | 108 | // see if the complex number is a whole value 109 | final def isWhole(d: Long): Boolean = real(d) % 1.0F == 0.0F && imag(d) % 1.0F == 0.0F 110 | 111 | // get the sign of the complex number 112 | final def signum(d: Long): Int = real(d) compare 0.0F 113 | 114 | // get the complex sign of the complex number 115 | final def complexSignum(d: Long): Long = { 116 | val m = Math.abs(d) 117 | if (m == 0.0F) zero else divide(d, encode(m.toFloat, 0.0F)) 118 | } 119 | 120 | // negation 121 | final def negate(a: Long): Long = encode(-real(a), -imag(a)) 122 | 123 | // addition 124 | final def add(a: Long, b: Long): Long = encode(real(a) + real(b), imag(a) + imag(b)) 125 | 126 | // subtraction 127 | final def subtract(a: Long, b: Long): Long = encode(real(a) - real(b), imag(a) - imag(b)) 128 | 129 | // multiplication 130 | final def multiply(a: Long, b: Long): Long = { 131 | val re_a = real(a) 132 | val im_a = imag(a) 133 | val re_b = real(b) 134 | val im_b = imag(b) 135 | encode(re_a * re_b - im_a * im_b, im_a * re_b + re_a * im_b) 136 | } 137 | 138 | // division 139 | final def divide(a: Long, b: Long): Long = { 140 | val re_a = real(a) 141 | val im_a = imag(a) 142 | val re_b = real(b) 143 | val im_b = imag(b) 144 | 145 | val abs_re_b = Math.abs(re_b) 146 | val abs_im_b = Math.abs(im_b) 147 | 148 | if (abs_re_b >= abs_im_b) 149 | if (abs_re_b == 0.0F) throw new ArithmeticException("/0") 150 | val ratio = im_b / re_b 151 | val denom = re_b + im_b * ratio 152 | encode((re_a + im_a * ratio) / denom, (im_a - re_a * ratio) / denom) 153 | else 154 | if (abs_im_b == 0.0F) throw new ArithmeticException("/0") 155 | val ratio = re_b / im_b 156 | val denom = re_b * ratio + im_b 157 | encode((re_a * ratio + im_a) / denom, (im_a * ratio - re_a) / denom) 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/main/scala/spire/math/Rat.scala: -------------------------------------------------------------------------------- 1 | package spire.math 2 | 3 | import spire.algebra._ 4 | 5 | final class Rat(val num: BigInt, val den: BigInt) extends Serializable { lhs => 6 | 7 | override def toString: String = 8 | if (den == 1) s"$num" else s"$num/$den" 9 | 10 | override def equals(that: Any): Boolean = 11 | that match { 12 | case r: Rat => num == r.num && den == r.den 13 | case _ => false 14 | } 15 | 16 | override def hashCode(): Int = (num, den).## 17 | 18 | def isZero: Boolean = num == 0 19 | 20 | def isOne: Boolean = num == 1 && den == 1 21 | 22 | def compare(rhs: Rat): Int = 23 | (lhs.num * rhs.den) `compare` (rhs.num * lhs.den) 24 | 25 | def abs(): Rat = Rat(num.abs, den) 26 | 27 | def signum(): Int = num.signum 28 | 29 | def +(rhs: Rat): Rat = 30 | Rat((lhs.num * rhs.den) + (rhs.num * lhs.den), (lhs.den * rhs.den)) 31 | 32 | def unary_- : Rat = 33 | Rat(-lhs.num, lhs.den) 34 | 35 | def *(rhs: Rat): Rat = 36 | Rat(lhs.num * rhs.num, lhs.den * rhs.den) 37 | 38 | def /~(rhs: Rat) = lhs / rhs 39 | 40 | def %(rhs: Rat) = Rat.zero 41 | 42 | def reciprocal: Rat = 43 | if (num == 0) throw new ArithmeticException("/0") else Rat(den, num) 44 | 45 | def /(rhs: Rat): Rat = 46 | lhs * rhs.reciprocal 47 | 48 | def **(k: Int): Rat = 49 | Rat(num.pow(k), den.pow(k)) 50 | 51 | def toDouble: Double = num.toDouble / den.toDouble 52 | 53 | def toInt: Int = toDouble.toInt 54 | 55 | def isWhole: Boolean = den == 1 56 | 57 | def ceil: Rat = 58 | if (num >= 0) Rat((num + den - 1) / den, 1) 59 | else Rat(num / den, 1) 60 | 61 | def floor: Rat = 62 | if (num >= 0) Rat(num / den, 1) 63 | else Rat((num - den + 1) / den, 1) 64 | 65 | def round: Rat = 66 | if (num >= 0) Rat((num + (den / 2)) / den, 1) 67 | else Rat((num - (den / 2)) / den, 1) 68 | 69 | } 70 | 71 | object Rat { 72 | 73 | val zero: Rat = Rat(0) 74 | val one: Rat = Rat(1) 75 | 76 | def apply(n: BigInt): Rat = 77 | Rat(n, 1) 78 | 79 | def apply(num: BigInt, den: BigInt): Rat = 80 | if (den == 0) throw new ArithmeticException("/0") 81 | else if (den < 0) apply(-num, -den) 82 | else if (num == 0) new Rat(0, 1) 83 | else { 84 | val g = num `gcd` den 85 | new Rat(num / g, den / g) 86 | } 87 | 88 | def unapply(r: Rat): (BigInt, BigInt) = (r.num, r.den) 89 | 90 | given Order[Rat] with Field[Rat] with { 91 | 92 | def compare(x: Rat, y: Rat): Int = x `compare` y 93 | 94 | val zero: Rat = Rat.zero 95 | val one: Rat = Rat.one 96 | 97 | def plus(a: Rat, b: Rat): Rat = a + b 98 | def negate(a: Rat): Rat = -a 99 | def times(a: Rat, b: Rat): Rat = a * b 100 | override def reciprocal(a: Rat): Rat = a.reciprocal 101 | def div(a: Rat, b: Rat): Rat = a / b 102 | 103 | override def fromInt(n: Int): Rat = Rat(n) 104 | override def fromBigInt(n: BigInt): Rat = Rat(n) 105 | 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/scala/spire/math/Sorting.scala: -------------------------------------------------------------------------------- 1 | package spire.math 2 | 3 | import spire.algebra.Order 4 | import spire.syntax.order.given 5 | 6 | import scala.reflect.ClassTag 7 | 8 | /** 9 | * Interface for a sorting strategy object. 10 | */ 11 | trait Sort extends Any { 12 | def sort[@specialized A: Order: ClassTag](data: Array[A]): Unit 13 | } 14 | 15 | /** 16 | * An implementation of insertion sort. 17 | * 18 | * Works well for small arrays but due to quadratic complexity is not generally optimal. 19 | */ 20 | object InsertionSort extends Sort { 21 | 22 | /** 23 | * Sorts `data` in place using insertion sort. 24 | * 25 | * @param data the array to be sorted 26 | * @tparam A a member of the type class `Order` 27 | */ 28 | final def sort[@specialized A: Order: ClassTag](data: Array[A]): Unit = 29 | sort(data, 0, data.length) 30 | 31 | /** 32 | * Uses insertion sort on `data` to sort the entries from the index `start` 33 | * up to, but not including, the index `end`. Operates in place. 34 | * 35 | * @param data the array to be sorted 36 | * @param start the index of the first element, inclusive, to be sorted 37 | * @param end the index of the last element, exclusive, to be sorted 38 | * @tparam A a member of the type class `Order` 39 | */ 40 | final def sort[@specialized A: Order: ClassTag](data: Array[A], start: Int, end: Int): Unit = { 41 | require(start <= end && start >= 0 && end <= data.length) 42 | var i = start + 1 43 | while (i < end) { 44 | val item = data(i) 45 | var hole = i 46 | while (hole > start && data(hole - 1) > item) { 47 | data(hole) = data(hole - 1) 48 | hole -= 1 49 | } 50 | data(hole) = item 51 | i += 1 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * In-place quicksort implementation. It is not stable, but does not allocate 58 | * extra space (other than stack). It uses InsertionSort for sorting very small arrays. 59 | */ 60 | object QuickSort { 61 | inline val limit = 16 62 | 63 | /** 64 | * Uses quicksort on `data` to sort the entries. Operates in place. 65 | * 66 | * If the size of the input array is less than the threshold `limit`, 67 | * uses insertion sort instead. 68 | * 69 | * @param data the array to be sorted 70 | * @tparam A a member of the type class `Order` 71 | */ 72 | final def sort[@specialized A: Order: ClassTag](data: Array[A]): Unit = qsort(data, 0, data.length) 73 | 74 | /** 75 | * Uses quicksort on `data` to sort the entries from the index `start` 76 | * up to, but not including, the index `end`. Operates in place. 77 | * 78 | * If the size of the segment to be sorted is less than the threshold `limit` 79 | * uses insertion sort instead. 80 | * 81 | * @param data the array to be sorted 82 | * @param start the index from which to start sorting (inclusive) 83 | * @param end the index at which to stop sorting (exclusive) 84 | * @tparam A a member of the type class `Order` 85 | */ 86 | final def qsort[@specialized A: Order: ClassTag](data: Array[A], start: Int, end: Int): Unit = { 87 | require(start >= 0 && end <= data.length) 88 | if (end - start < limit) { 89 | InsertionSort.sort(data, start, end) 90 | return 91 | } 92 | 93 | val pivotIndex = start + (end - start) / 2 94 | val nextPivotIndex = partition(data, start, end, pivotIndex) 95 | qsort(data, start, nextPivotIndex) 96 | qsort(data, nextPivotIndex + 1, end) 97 | } 98 | 99 | /** 100 | * Helper method for the quick sort implementation. Partitions the segment of the array `data` from `start` to `end` 101 | * according to the value at the given `pivotIndex`. Values in the segment less than the pivot value will end up 102 | * to the left of the pivot value, and values greater on the right. Operates in place. 103 | * 104 | * @param data the array to be partitioned 105 | * @param start the left endpoint (inclusive) of the interval to be partitioned 106 | * @param end the right endpoint (exclusive) of the interval to be partitioned 107 | * @param pivotIndex the index of the current pivot 108 | * @tparam A a member of the type class Order 109 | * @return the next pivot value 110 | */ 111 | final def partition[@specialized A: Order: ClassTag](data: Array[A], start: Int, end: Int, pivotIndex: Int): Int = { 112 | require(start >= 0 && pivotIndex >= start && end > pivotIndex && end <= data.length) 113 | val pivotValue = data(pivotIndex) 114 | 115 | data(pivotIndex) = data(end - 1) 116 | 117 | var temp = pivotValue 118 | var store = start 119 | var i = start 120 | while (i < end - 1) { 121 | if (data(i) < pivotValue) { 122 | //swap(i, store) 123 | temp = data(i); data(i) = data(store); data(store) = temp 124 | store += 1 125 | } 126 | i += 1 127 | } 128 | 129 | data(end - 1) = data(store) 130 | data(store) = pivotValue 131 | store 132 | } 133 | } 134 | 135 | // TODO: it would be nice to try implementing some hybrid sorts, for instance 136 | // Tim Peters' sort algorithm. 137 | 138 | /** 139 | * Object providing in-place sorting capability for arrays. 140 | * 141 | * Sorting.sort() uses quickSort() by default (in-place, not stable, generally 142 | * fastest but might hit bad cases where it is quadratic. Also provides 143 | * insertionSort(), which is slow except for small arrays. 144 | */ 145 | object Sorting { 146 | /** Delegates to [[spire.math.QuickSort.sort]] */ 147 | final def sort[@specialized A: Order: ClassTag](data: Array[A]): Unit = QuickSort.sort(data) 148 | 149 | /** Delegates to [[spire.math.InsertionSort.sort]] */ 150 | final def insertionSort[@specialized A: Order: ClassTag](data: Array[A]): Unit = InsertionSort.sort(data) 151 | 152 | /** Delegates to [[spire.math.QuickSort.sort]] */ 153 | final def quickSort[@specialized A: Order: ClassTag](data: Array[A]): Unit = QuickSort.sort(data) 154 | } 155 | -------------------------------------------------------------------------------- /src/main/scala/spire/math/UInt.scala: -------------------------------------------------------------------------------- 1 | package spire.math 2 | 3 | import spire.algebra.{CRig, Order} 4 | 5 | object UInt { 6 | 7 | given Order[UInt] with CRig[UInt] with { 8 | 9 | // Order 10 | 11 | def compare(x: UInt, y: UInt): Int = if (x < y) -1 else if (x > y) 1 else 0 12 | override def eqv(x:UInt, y:UInt): Boolean = x == y 13 | override def neqv(x:UInt, y:UInt): Boolean = x != y 14 | override def gt(x: UInt, y: UInt): Boolean = x > y 15 | override def gteqv(x: UInt, y: UInt): Boolean = x >= y 16 | override def lt(x: UInt, y: UInt): Boolean = x < y 17 | override def lteqv(x: UInt, y: UInt): Boolean = x <= y 18 | 19 | // CRig 20 | 21 | def one: UInt = UInt(1) 22 | def plus(a:UInt, b:UInt): UInt = a + b 23 | override def times(a:UInt, b:UInt): UInt = a * b 24 | def zero: UInt = UInt(0) 25 | 26 | } 27 | 28 | private inline def fromLong(l: Long): UInt = UInt(l.toInt) 29 | 30 | @inline final val MinValue: UInt = UInt(0) 31 | @inline final val MaxValue: UInt = UInt(-1) 32 | } 33 | 34 | class UInt(val signed: Int) extends AnyVal { 35 | def toByte: Byte = signed.toByte 36 | def toChar: Char = signed.toChar 37 | def toShort: Short = signed.toShort 38 | def toInt: Int = signed 39 | def toLong: Long = signed & 0xffffffffL 40 | def toFloat: Float = toLong.toFloat 41 | def toDouble: Double = toLong.toDouble 42 | def toBigInt: BigInt = BigInt(toLong) 43 | 44 | def isValidByte: Boolean = toInt == toByte 45 | def isValidShort: Boolean = toInt == toShort 46 | def isValidChar: Boolean = toInt == toChar 47 | def isValidInt: Boolean = signed >= 0 48 | def isValidLong: Boolean = true 49 | 50 | override def toString: String = toLong.toString 51 | 52 | def == (that: UInt): Boolean = this.signed == that.signed 53 | def != (that: UInt): Boolean = this.signed != that.signed 54 | 55 | def ===(that: UInt): Boolean = this.signed == that.signed 56 | def =!=(that: UInt): Boolean = this.signed != that.signed 57 | 58 | def <= (that: UInt): Boolean = this.toLong <= that.toLong 59 | def < (that: UInt): Boolean = this.toLong < that.toLong 60 | def >= (that: UInt): Boolean = this.toLong >= that.toLong 61 | def > (that: UInt): Boolean = this.toLong > that.toLong 62 | 63 | def unary_- : UInt = UInt(-this.signed) 64 | 65 | def + (that: UInt): UInt = UInt(this.signed + that.signed) 66 | def - (that: UInt): UInt = UInt(this.signed - that.signed) 67 | def * (that: UInt): UInt = UInt(this.signed * that.signed) 68 | def / (that: UInt): UInt = UInt.fromLong(this.toLong / that.toLong) 69 | def % (that: UInt): UInt = UInt.fromLong(this.toLong % that.toLong) 70 | 71 | def unary_~ : UInt = UInt(~this.signed) 72 | 73 | def << (shift: Int): UInt = UInt(signed << shift) 74 | def >> (shift: Int): UInt = UInt(signed >>> shift) 75 | def >>> (shift: Int): UInt = UInt(signed >>> shift) 76 | def & (that: UInt): UInt = UInt(this.signed & that.signed) 77 | def | (that: UInt): UInt = UInt(this.signed | that.signed) 78 | def ^ (that: UInt): UInt = UInt(this.signed ^ that.signed) 79 | } 80 | -------------------------------------------------------------------------------- /src/main/scala/spire/math/ULong.scala: -------------------------------------------------------------------------------- 1 | package spire.math 2 | 3 | import spire.algebra.{CRig, Order} 4 | import java.lang.Math 5 | import scala.annotation.tailrec 6 | 7 | object ULong { 8 | 9 | given Order[ULong] with CRig[ULong] with { 10 | 11 | // Order 12 | 13 | def compare(x: ULong, y: ULong): Int = if (x < y) -1 else if (x > y) 1 else 0 14 | override def eqv(x:ULong, y:ULong): Boolean = x == y 15 | override def neqv(x:ULong, y:ULong): Boolean = x != y 16 | override def gt(x: ULong, y: ULong): Boolean = x > y 17 | override def gteqv(x: ULong, y: ULong): Boolean = x >= y 18 | override def lt(x: ULong, y: ULong): Boolean = x < y 19 | override def lteqv(x: ULong, y: ULong): Boolean = x <= y 20 | 21 | // CRig 22 | 23 | def one: ULong = ULong(1) 24 | def plus(a:ULong, b:ULong): ULong = a + b 25 | override def times(a:ULong, b:ULong): ULong = a * b 26 | def zero: ULong = ULong(0) 27 | 28 | } 29 | 30 | inline def apply(n: Long): ULong = new ULong(n) 31 | 32 | final def apply(s: String): ULong = fromBigInt(BigInt(s)) 33 | 34 | final def fromInt(n: Int): ULong = new ULong(n & 0xffffffffL) 35 | final def fromLong(n: Long): ULong = new ULong(n) 36 | 37 | final def fromBigInt(n: BigInt): ULong = 38 | if (n < 0) throw new IllegalArgumentException(s"$n < 0") 39 | else new ULong(n.toLong) 40 | 41 | given ulongToBigInt: Conversion[ULong, BigInt] = _.toBigInt 42 | 43 | @inline final val MinValue = ULong(0L) 44 | @inline final val MaxValue = ULong(-1L) 45 | 46 | @tailrec final private[math] def pow(t:Long, b:Long, e:Long): ULong = { 47 | if (e == 0L) new ULong(t) 48 | else if ((e & 1L) == 1L) pow(t * b, b * b, e >>> 1L) 49 | else pow(t, b * b, e >>> 1L) 50 | } 51 | 52 | @tailrec final private[math] def gcd(a:ULong, b:ULong): ULong = { 53 | if (b == new ULong(0L)) a else gcd(b, a % b) 54 | } 55 | 56 | private[spire] final val LimitAsDouble: Double = Math.pow(2.0, 64) 57 | 58 | private[spire] final val LimitAsBigInt: BigInt = 59 | BigInt(1) << 64 60 | 61 | } 62 | 63 | class ULong(val signed: Long) extends AnyVal { 64 | final def toByte: Byte = signed.toByte 65 | final def toChar: Char = signed.toChar 66 | final def toShort: Short = signed.toShort 67 | final def toInt: Int = signed.toInt 68 | final def toLong: Long = signed 69 | 70 | final def toFloat: Float = { 71 | if (signed < 0) (ULong.LimitAsDouble + signed.toDouble).toFloat 72 | else signed.toFloat 73 | } 74 | 75 | // FIXME: it would be nice to write some "real" floating-point code 76 | // to correctly find the nearest Double. 77 | final def toDouble: Double = 78 | toBigInt.toDouble 79 | 80 | final def toBigInt: BigInt = 81 | if (signed < 0) ULong.LimitAsBigInt + signed 82 | else BigInt(signed) 83 | 84 | // FIXME: it would be nice to avoid converting to BigInt here 85 | override final def toString: String = 86 | if (signed >= 0L) signed.toString 87 | else (ULong.LimitAsBigInt + signed).toString 88 | 89 | // TODO: replace these with `===` and `=!=`? Don't we get `==` and `!=` for free with value classes? 90 | final def == (that: ULong): Boolean = this.signed == that.signed 91 | final def != (that: ULong): Boolean = this.signed != that.signed 92 | 93 | final def === (that: ULong): Boolean = this.signed == that.signed 94 | final def =!= (that: ULong): Boolean = this.signed != that.signed 95 | 96 | final def <= (that: ULong): Boolean = if (this.signed >= 0L) 97 | this.signed <= that.signed || that.signed < 0L 98 | else 99 | that.signed >= this.signed && that.signed < 0L 100 | 101 | final def < (that: ULong): Boolean = if (this.signed >= 0L) 102 | this.signed < that.signed || that.signed < 0L 103 | else 104 | that.signed > this.signed && that.signed < 0L 105 | 106 | inline final def >= (that: ULong): Boolean = that <= this 107 | inline final def > (that: ULong): Boolean = that < this 108 | 109 | final def unary_- : ULong = ULong(-this.signed) 110 | 111 | final def + (that: ULong): ULong = ULong(this.signed + that.signed) 112 | final def - (that: ULong): ULong = ULong(this.signed - that.signed) 113 | final def * (that: ULong): ULong = ULong(this.signed * that.signed) 114 | 115 | final def / (that: ULong): ULong = { 116 | val n: Long = this.signed 117 | val d: Long = that.signed 118 | 119 | if (d == 0) { 120 | throw new java.lang.ArithmeticException("/ by zero") 121 | } else if (d < 0) { 122 | ULong(if (n >= 0 || n < d) 0L else 1L) 123 | } else if (n >= 0) { 124 | ULong(n / d) 125 | } else { 126 | val half = n >>> 1 127 | if (half < d) { 128 | ULong(1L) 129 | } else { 130 | ULong(((half / d) << 1) + (((half % d) << 1) + (n & 1)) / d) 131 | } 132 | } 133 | } 134 | 135 | final def % (that: ULong): ULong = this - (this / that) * that 136 | 137 | final def /% (that: ULong): (ULong, ULong) = { 138 | val q = this / that 139 | (q, this - q * that) 140 | } 141 | 142 | final def unary_~ : ULong = ULong(~this.signed) 143 | 144 | final def << (shift: Int): ULong = ULong(signed << shift) 145 | final def >> (shift: Int): ULong = ULong(signed >>> shift) 146 | final def >>> (shift: Int): ULong = ULong(signed >>> shift) 147 | final def & (that: ULong): ULong = ULong(this.signed & that.signed) 148 | final def | (that: ULong): ULong = ULong(this.signed | that.signed) 149 | final def ^ (that: ULong): ULong = ULong(this.signed ^ that.signed) 150 | 151 | final def ** (that: ULong): ULong = ULong.pow(1L, this.signed, that.signed) 152 | 153 | final def gcd (that: ULong): ULong = ULong.gcd(this, that) 154 | } 155 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/any.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | trait AnyInstances extends IntInstances 4 | with LongInstances 5 | with FloatInstances 6 | with DoubleInstances 7 | with BigIntegerInstances 8 | with BigDecimalInstances 9 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/bigDecimal.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | import java.math.MathContext 4 | 5 | import spire.algebra.{Field, Order} 6 | 7 | trait BigDecimalInstances { 8 | 9 | given Order[BigDecimal] with Field[BigDecimal] with { 10 | 11 | // Order 12 | 13 | override def eqv(x: BigDecimal, y: BigDecimal): Boolean = x == y 14 | override def neqv(x: BigDecimal, y: BigDecimal): Boolean = x != y 15 | override def gt(x: BigDecimal, y: BigDecimal): Boolean = x > y 16 | override def gteqv(x: BigDecimal, y: BigDecimal): Boolean = x >= y 17 | override def lt(x: BigDecimal, y: BigDecimal): Boolean = x < y 18 | override def lteqv(x: BigDecimal, y: BigDecimal): Boolean = x <= y 19 | 20 | // Scala compareTo has no guarantee to return only -1, 0 or 1 as per Spire compare contract, 21 | // so we call Java's compareTo which does 22 | def compare(x: BigDecimal, y: BigDecimal): Int = x.bigDecimal.compareTo(y.bigDecimal) 23 | 24 | // Field 25 | 26 | override def minus(a: BigDecimal, b: BigDecimal): BigDecimal = a - b 27 | def negate(a: BigDecimal): BigDecimal = -a 28 | val one: BigDecimal = BigDecimal(1.0) 29 | def plus(a: BigDecimal, b: BigDecimal): BigDecimal = a + b 30 | override def times(a: BigDecimal, b: BigDecimal): BigDecimal = a * b 31 | val zero: BigDecimal = BigDecimal(0.0) 32 | 33 | override def fromInt(n: Int): BigDecimal = BigDecimal(n) 34 | override def fromBigInt(n: BigInt): BigDecimal = BigDecimal(n) 35 | override def fromDouble(n: Double): BigDecimal = BigDecimal(n) 36 | override def fromBigDecimal(n: BigDecimal): BigDecimal = n 37 | 38 | def div(a: BigDecimal, b: BigDecimal): BigDecimal = a / b 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/bigInteger.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | import java.math.BigInteger 4 | 5 | import spire.algebra.{CRing, Eq, Order} 6 | 7 | trait BigIntegerInstances { 8 | 9 | given Order[BigInteger] with CRing[BigInteger] with { 10 | 11 | // Order 12 | 13 | def compare(x: BigInteger, y: BigInteger): Int = x compareTo y 14 | override def eqv(x:BigInteger, y:BigInteger): Boolean = x equals y 15 | override def neqv(x:BigInteger, y:BigInteger): Boolean = !(x equals y) 16 | override def gt(x: BigInteger, y: BigInteger): Boolean = (x compareTo y) > 0 17 | override def gteqv(x: BigInteger, y: BigInteger): Boolean = (x compareTo y) >= 0 18 | override def lt(x: BigInteger, y: BigInteger): Boolean = (x compareTo y) < 0 19 | override def lteqv(x: BigInteger, y: BigInteger): Boolean = (x compareTo y) <= 0 20 | 21 | // CRing 22 | 23 | override def minus(a: BigInteger, b: BigInteger): BigInteger = (a subtract b).nn 24 | def negate(a: BigInteger): BigInteger = a.negate.nn 25 | def one: BigInteger = BigInteger.ONE.nn 26 | def plus(a: BigInteger, b: BigInteger): BigInteger = (a add b).nn 27 | override def times(a: BigInteger, b: BigInteger): BigInteger = (a multiply b).nn 28 | def zero: BigInteger = BigInteger.ZERO.nn 29 | 30 | override def fromInt(n: Int): BigInteger = BigInteger.valueOf(n.toLong).nn 31 | override def fromBigInt(n: BigInt): BigInteger = n.underlying 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/double.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | import spire.algebra.{Field, Order} 4 | 5 | trait DoubleInstances { 6 | 7 | given Order[Double] with Field[Double] with { 8 | 9 | // Field 10 | override def minus(a:Double, b:Double): Double = a - b 11 | def negate(a:Double): Double = -a 12 | def one: Double = 1.0 13 | def plus(a:Double, b:Double): Double = a + b 14 | override def times(a:Double, b:Double): Double = a * b 15 | def zero: Double = 0.0 16 | 17 | override def fromInt(n: Int): Double = n.toDouble 18 | override def fromDouble(n: Double): Double = n 19 | 20 | def div(a:Double, b:Double): Double = a / b 21 | 22 | // Order 23 | override def eqv(x:Double, y:Double): Boolean = x == y 24 | override def neqv(x:Double, y:Double): Boolean = x != y 25 | override def gt(x: Double, y: Double): Boolean = x > y 26 | override def gteqv(x: Double, y: Double): Boolean = x >= y 27 | override def lt(x: Double, y: Double): Boolean = x < y 28 | override def lteqv(x: Double, y: Double): Boolean = x <= y 29 | def compare(x: Double, y: Double): Int = java.lang.Double.compare(x, y) 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/float.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | import spire.algebra.{Field, Order} 4 | 5 | trait FloatInstances { 6 | 7 | given Order[Float] with Field[Float] with { 8 | 9 | // Order 10 | 11 | def compare(x: Float, y: Float): Int = java.lang.Float.compare(x, y) 12 | override def eqv(x:Float, y:Float): Boolean = x == y 13 | override def neqv(x:Float, y:Float): Boolean = x != y 14 | override def gt(x: Float, y: Float): Boolean = x > y 15 | override def gteqv(x: Float, y: Float): Boolean = x >= y 16 | override def lt(x: Float, y: Float): Boolean = x < y 17 | override def lteqv(x: Float, y: Float): Boolean = x <= y 18 | 19 | // Field 20 | override def minus(a:Float, b:Float): Float = a - b 21 | def negate(a:Float): Float = -a 22 | def one: Float = 1.0F 23 | def plus(a:Float, b:Float): Float = a + b 24 | override def times(a:Float, b:Float): Float = a * b 25 | def zero: Float = 0.0F 26 | 27 | override def fromInt(n: Int): Float = n.toFloat 28 | override def fromDouble(n: Double): Float = n.toFloat 29 | 30 | def div(a:Float, b:Float): Float = a / b 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/int.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | import spire.algebra.{CRing, Order} 4 | 5 | trait IntInstances { 6 | 7 | given Order[Int] with CRing[Int] with { 8 | 9 | // Order 10 | 11 | def compare(x: Int, y: Int): Int = if (x < y) -1 else if (x == y) 0 else 1 12 | override def eqv(x: Int, y: Int): Boolean = x == y 13 | override def neqv(x: Int, y: Int): Boolean = x != y 14 | override def gt(x: Int, y: Int): Boolean = x > y 15 | override def gteqv(x: Int, y: Int): Boolean = x >= y 16 | override def lt(x: Int, y: Int): Boolean = x < y 17 | override def lteqv(x: Int, y: Int): Boolean = x <= y 18 | 19 | // CRing 20 | 21 | override def minus(a:Int, b:Int): Int = a - b 22 | def negate(a:Int): Int = -a 23 | def one: Int = 1 24 | def plus(a:Int, b:Int): Int = a + b 25 | override def times(a:Int, b:Int): Int = a * b 26 | def zero: Int = 0 27 | override def fromInt(n: Int): Int = n 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/long.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | import spire.algebra.{Order, CRing} 4 | 5 | trait LongInstances { 6 | 7 | given Order[Long] with CRing[Long] with { 8 | 9 | // CRing 10 | 11 | override def minus(a:Long, b:Long): Long = a - b 12 | def negate(a:Long): Long = -a 13 | def one: Long = 1L 14 | def plus(a:Long, b:Long): Long = a + b 15 | override def times(a:Long, b:Long): Long = a * b 16 | def zero: Long = 0L 17 | override def fromInt(n: Int): Long = n.toLong 18 | 19 | // Order 20 | 21 | override def eqv(x:Long, y:Long): Boolean = x == y 22 | override def neqv(x:Long, y:Long): Boolean = x != y 23 | override def gt(x: Long, y: Long): Boolean = x > y 24 | override def gteqv(x: Long, y: Long): Boolean = x >= y 25 | override def lt(x: Long, y: Long): Boolean = x < y 26 | override def lteqv(x: Long, y: Long): Boolean = x <= y 27 | def compare(x: Long, y: Long): Int = if (x < y) -1 else if (x == y) 0 else 1 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/spire/std/package.scala: -------------------------------------------------------------------------------- 1 | package spire.std 2 | 3 | object any extends AnyInstances 4 | object int extends IntInstances 5 | object long extends LongInstances 6 | object float extends FloatInstances 7 | object double extends DoubleInstances 8 | object bigInteger extends BigIntegerInstances 9 | object bigDecimal extends BigDecimalInstances 10 | -------------------------------------------------------------------------------- /src/main/scala/spire/syntax/Literals.scala: -------------------------------------------------------------------------------- 1 | package spire.syntax 2 | 3 | import spire.algebra.{Field, CRing} 4 | 5 | import scala.quoted._ 6 | 7 | import scala.util.FromDigits 8 | 9 | object literals { 10 | 11 | given [A](using ev: CRing[A]): RadixLiteral[A] with 12 | override inline def fromDigits(digits: String): A = 13 | ${ macros.fromRingImpl('digits, '{10}, 'ev) } 14 | override inline def fromDigits(digits: String, radix: Int): A = 15 | ${ macros.fromRingImpl('digits, 'radix, 'ev) } 16 | 17 | given [A](using ev: Field[A]): FloatingLiteral[A] with 18 | override inline def fromDigits(digits: String): A = 19 | ${ macros.fromFieldImpl('digits, 'ev) } 20 | 21 | class RadixLiteral[A](using A: CRing[A]) extends FromDigits.WithRadix[A]: 22 | override def fromDigits(digits: String): A = fromDigits(digits, 10) 23 | override def fromDigits(digits: String, radix: Int): A = A.fromBigInt(BigInt(digits, radix)) 24 | 25 | class FloatingLiteral[A](using A: Field[A]) extends FromDigits.Floating[A]: 26 | override def fromDigits(digits: String): A = A.fromBigDecimal(BigDecimal(digits)) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/scala/spire/syntax/Syntax.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | package syntax 3 | 4 | import spire.algebra._ 5 | 6 | trait EqSyntax: 7 | given EqOps: AnyRef with 8 | extension [A: Eq, B](lhs: A)(using ev1: B =:= A) 9 | inline def ===(rhs: B): Boolean = Eq[A].eqv(lhs, ev1(rhs)) 10 | inline def =!=(rhs: B): Boolean = Eq[A].neqv(lhs, ev1(rhs)) 11 | 12 | trait PartialOrderSyntax extends EqSyntax: 13 | given PartialOrderOps: AnyRef with 14 | extension [A: PartialOrder](lhs: A) 15 | inline def >(rhs: A): Boolean = PartialOrder[A].gt(lhs, rhs) 16 | inline def >=(rhs: A): Boolean = PartialOrder[A].gteqv(lhs, rhs) 17 | inline def <(rhs: A): Boolean = PartialOrder[A].lt(lhs, rhs) 18 | inline def <=(rhs: A): Boolean = PartialOrder[A].lteqv(lhs, rhs) 19 | 20 | inline def partialCompare(rhs: A): Double = PartialOrder[A].partialCompare(lhs, rhs) 21 | inline def tryCompare(rhs: A): Option[Int] = PartialOrder[A].tryCompare(lhs, rhs) 22 | 23 | trait OrderSyntax extends PartialOrderSyntax: 24 | given OrderOps: AnyRef with 25 | extension [A: Order](lhs: A) 26 | inline def compare(rhs: A): Int = Order[A].compare(lhs, rhs) 27 | 28 | trait CRigSyntax: 29 | given CRigOps: AnyRef with 30 | extension [A: CRig](lhs: A) 31 | inline def +(rhs: A): A = CRig[A].plus(lhs, rhs) 32 | inline def isZero(using Eq[A]): Boolean = CRig[A].isZero(lhs) 33 | inline def *(rhs: A): A = CRig[A].times(lhs, rhs) 34 | inline def isOne(using Eq[A]): Boolean = CRig[A].isOne(lhs) 35 | 36 | trait CRingSyntax extends CRigSyntax: 37 | given CRingOps: AnyRef with 38 | extension [A: CRing](lhs: A) 39 | inline def unary_- : A = CRing[A].negate(lhs) 40 | inline def -(rhs: A): A = CRing[A].minus(lhs, rhs) 41 | 42 | trait FieldSyntax extends CRingSyntax: 43 | given FieldOps: AnyRef with 44 | extension [A: Field](lhs: A) 45 | inline def reciprocal(): A = Field[A].reciprocal(lhs) 46 | inline def /(rhs: A): A = Field[A].div(lhs, rhs) 47 | 48 | trait CforSyntax: 49 | import macros._ 50 | import collection.immutable.NumericRange 51 | 52 | final type RangeLike = Range | NumericRange[Long] 53 | 54 | final type RangeElem[X <: RangeLike] = X match 55 | case Range => Int 56 | case NumericRange[Long] => Long 57 | 58 | inline def cfor[A](inline init: A)(inline test: A => Boolean, inline next: A => A)(inline body: A => Unit): Unit = 59 | cforInline(init, test, next, body) 60 | 61 | inline def cforRange[R <: RangeLike](inline r: R)(inline body: RangeElem[R] => Unit): Unit = 62 | ${ cforRangeMacroGen('r, 'body) } 63 | 64 | inline def cforRange2[R <: RangeLike](inline r1: R, inline r2: R)(inline body: (RangeElem[R], RangeElem[R]) => Unit): Unit = 65 | cforRange(r1) { x => cforRange(r2) { y => body(x, y) } } 66 | 67 | given CforOps: AnyRef with 68 | /** Alias of [[cforRange]] as an infix method. 69 | */ 70 | extension [R <: RangeLike](inline r: R) inline def peek(inline body: RangeElem[R] => Unit): Unit = 71 | cforRange(r)(body) 72 | 73 | trait AllSyntax extends CforSyntax 74 | with EqSyntax 75 | with PartialOrderSyntax 76 | with OrderSyntax 77 | with CRigSyntax 78 | with CRingSyntax 79 | with FieldSyntax 80 | -------------------------------------------------------------------------------- /src/main/scala/spire/syntax/macros/cforMacros.scala: -------------------------------------------------------------------------------- 1 | package spire.syntax.macros 2 | 3 | import quoted._ 4 | import collection.immutable.NumericRange 5 | 6 | import spire.syntax.cfor.{RangeLike, RangeElem} 7 | 8 | inline def cforInline[R](inline init: R, inline test: R => Boolean, inline next: R => R, inline body: R => Unit): Unit = 9 | var index = init 10 | while test(index) do 11 | body(index) 12 | index = next(index) 13 | 14 | def cforRangeMacroGen[R <: RangeLike : Type](r: Expr[R], body: Expr[RangeElem[R] => Unit])(using Quotes): Expr[Unit] = 15 | import quotes.reflect.{_, given} 16 | 17 | type RangeL = NumericRange[Long] 18 | 19 | (r, body) match 20 | case '{$r: Range } -> '{$body: (Int => Unit) } => cforRangeMacro(r, body) 21 | case '{$r: NumericRange[Long]} -> '{$body: (Long => Unit)} => cforRangeMacroLong(r, body) 22 | // case '{$r: $t} -> _ => report.errorAndAbort(s"Uneligable Range type ${t.show}", r); '{} 23 | 24 | end cforRangeMacroGen 25 | 26 | def cforRangeMacroLong(r: Expr[NumericRange[Long]], body: Expr[Long => Unit])(using Quotes): Expr[Unit] = 27 | import quotes.reflect.{*, given} 28 | 29 | def strideUpUntil(fromExpr: Expr[Long], untilExpr: Expr[Long], stride: Expr[Long]): Expr[Unit] = '{ 30 | var index = $fromExpr 31 | val limit = $untilExpr 32 | while index < limit do 33 | ${ Expr.betaReduce(body) }(index) 34 | index += $stride 35 | } 36 | 37 | def strideUpTo(fromExpr: Expr[Long], untilExpr: Expr[Long], stride: Expr[Long]): Expr[Unit] = '{ 38 | var index = $fromExpr 39 | val end = $untilExpr 40 | while index <= end do 41 | ${ Expr.betaReduce('{$body(index)}) } 42 | index += $stride 43 | } 44 | 45 | def strideDownTo(fromExpr: Expr[Long], untilExpr: Expr[Long], stride: Expr[Long]): Expr[Unit] = '{ 46 | var index = $fromExpr 47 | val end = $untilExpr 48 | while index >= end do 49 | ${ Expr.betaReduce('{$body(index)}) } 50 | index -= $stride 51 | } 52 | 53 | def strideDownUntil(fromExpr: Expr[Long], untilExpr: Expr[Long], stride: Expr[Long]): Expr[Unit] = '{ 54 | var index = $fromExpr 55 | val limit = $untilExpr 56 | while index > limit do 57 | ${ Expr.betaReduce('{$body(index)}) } 58 | index -= $stride 59 | } 60 | 61 | r match 62 | case '{ ($i: Long) until $j } => strideUpUntil(i,j,Expr(1L)) 63 | case '{ ($i: Long) to $j } => strideUpTo(i,j,Expr(1L)) 64 | 65 | case '{ ($i: Long) until $j by $step } => 66 | step match { 67 | case Expr(k) if k > 0 => strideUpUntil(i,j,Expr(k)) 68 | case Expr(k) if k < 0 => strideDownUntil(i,j,Expr(-k)) 69 | case Expr(k) if k == 0 => report.errorAndAbort("zero stride", step) 70 | 71 | case _ => 72 | report.warning(s"defaulting to foreach, can not optimise non-constant step", step) 73 | '{ val b = $body; $r.foreach(b) } 74 | } 75 | 76 | case '{ ($i: Long) to $j by $step } => 77 | step match { 78 | case Expr(k) if k > 0 => strideUpTo(i,j,Expr(k)) 79 | case Expr(k) if k < 0 => strideDownTo(i,j,Expr(-k)) 80 | case Expr(k) if k == 0 => report.errorAndAbort("zero stride", step) 81 | 82 | case _ => 83 | report.warning(s"defaulting to foreach, can not optimise non-constant step", step) 84 | '{ val b = $body; $r.foreach(b) } 85 | } 86 | 87 | case _ => 88 | report.warning(s"defaulting to foreach, can not optimise range expression", r) 89 | '{ val b = $body; $r.foreach(b) } 90 | 91 | end cforRangeMacroLong 92 | 93 | def cforRangeMacro(r: Expr[Range], body: Expr[Int => Unit])(using Quotes): Expr[Unit] = 94 | import quotes.reflect.{*, given} 95 | 96 | def strideUpUntil(fromExpr: Expr[Int], untilExpr: Expr[Int], stride: Expr[Int]): Expr[Unit] = '{ 97 | var index = $fromExpr 98 | val limit = $untilExpr 99 | while (index < limit) { 100 | ${ Expr.betaReduce('{ $body(index) }) } 101 | index += $stride 102 | } 103 | } 104 | 105 | def strideUpTo(fromExpr: Expr[Int], untilExpr: Expr[Int], stride: Expr[Int]): Expr[Unit] = '{ 106 | var index = $fromExpr 107 | val end = $untilExpr 108 | while (index <= end) { 109 | ${ Expr.betaReduce('{ $body(index) }) } 110 | index += $stride 111 | } 112 | } 113 | 114 | def strideDownTo(fromExpr: Expr[Int], untilExpr: Expr[Int], stride: Expr[Int]): Expr[Unit] = '{ 115 | var index = $fromExpr 116 | val end = $untilExpr 117 | while (index >= end) { 118 | ${ Expr.betaReduce('{ $body(index) }) } 119 | index -= $stride 120 | } 121 | } 122 | 123 | def strideDownUntil(fromExpr: Expr[Int], untilExpr: Expr[Int], stride: Expr[Int]): Expr[Unit] = '{ 124 | var index = $fromExpr 125 | val limit = $untilExpr 126 | while (index > limit) { 127 | ${ Expr.betaReduce('{ $body(index) }) } 128 | index -= $stride 129 | } 130 | } 131 | 132 | r match 133 | case '{ ($i: Int) until $j } => strideUpUntil(i,j,Expr(1)) 134 | case '{ ($i: Int) to $j } => strideUpTo(i,j,Expr(1)) 135 | 136 | case '{ ($i: Int) until $j by $step } => 137 | step match { 138 | case Expr(k) if k > 0 => strideUpUntil(i,j,Expr(k)) 139 | case Expr(k) if k < 0 => strideDownUntil(i,j,Expr(-k)) 140 | case Expr(k) if k == 0 => report.errorAndAbort("zero stride", step) 141 | 142 | case _ => 143 | report.warning(s"defaulting to foreach, can not optimise non-constant step", step) 144 | '{ val b = $body; $r.foreach(b) } 145 | } 146 | 147 | case '{ ($i: Int) to $j by $step } => 148 | step match { 149 | case Expr(k) if k > 0 => strideUpTo(i,j,Expr(k)) 150 | case Expr(k) if k < 0 => strideDownTo(i,j,Expr(-k)) 151 | case Expr(k) if k == 0 => report.errorAndAbort("zero stride", step) 152 | 153 | case _ => 154 | report.warning(s"defaulting to foreach, can not optimise non-constant step", step) 155 | '{ val b = $body; $r.foreach(b) } 156 | } 157 | 158 | case _ => 159 | report.warning(s"defaulting to foreach, can not optimise range expression", r) 160 | '{ val b = $body; $r.foreach(b) } 161 | 162 | end cforRangeMacro 163 | -------------------------------------------------------------------------------- /src/main/scala/spire/syntax/macros/genericLiteralMacros.scala: -------------------------------------------------------------------------------- 1 | package spire.syntax.macros 2 | 3 | import scala.quoted.* 4 | 5 | import spire.algebra.{Field, CRing} 6 | 7 | def fromRingImpl[A: Type](digits: Expr[String], radix: Expr[Int], A: Expr[CRing[A]])(using Quotes): Expr[A] = 8 | (digits -> radix): @unchecked match 9 | case Expr(ds) -> Expr(r) => fromBigIntImpl(BigInt(ds, r), A) 10 | case _ => '{ $A.fromBigInt(BigInt($digits, $radix)) } 11 | 12 | def fromFieldImpl[A: Type](digits: Expr[String], A: Expr[Field[A]])(using Quotes): Expr[A] = 13 | digits match 14 | case Expr(ds) => 15 | if floating.matches(ds) then 16 | val bigdec = BigDecimal(ds) 17 | if bigdec.isDecimalDouble || bigdec.isBinaryDouble || bigdec.isExactDouble then bigdec.toDouble match 18 | case 0.0 => '{ $A.zero } 19 | case 1.0 => '{ $A.one } 20 | case n => '{ $A.fromDouble(${ Expr(n) }) } 21 | else 22 | '{ $A.fromBigDecimal(${ Expr(bigdec) }) } 23 | else 24 | fromBigIntImpl(BigInt(ds), A) 25 | 26 | case _ => '{ $A.fromBigDecimal(BigDecimal($digits)) } 27 | 28 | private def fromBigIntImpl[A: Type](bigint: BigInt, A: Expr[CRing[A]])(using Quotes): Expr[A] = 29 | if bigint.isValidInt then bigint.toInt match 30 | case 0 => '{ $A.zero } 31 | case 1 => '{ $A.one } 32 | case n => '{ $A.fromInt(${ Expr(n) }) } 33 | else '{ $A.fromBigInt(${ Expr(bigint) }) } 34 | 35 | private val floating = """.*[.eE].*""".r 36 | -------------------------------------------------------------------------------- /src/main/scala/spire/syntax/package.scala: -------------------------------------------------------------------------------- 1 | package spire.syntax 2 | 3 | object cfor extends CforSyntax 4 | object eq extends EqSyntax 5 | object partialOrder extends PartialOrderSyntax 6 | object order extends OrderSyntax 7 | object rig extends CRigSyntax 8 | object ring extends CRingSyntax 9 | object field extends FieldSyntax 10 | object all extends AllSyntax 11 | -------------------------------------------------------------------------------- /src/main/scala/spire/syntax/primitives.scala: -------------------------------------------------------------------------------- 1 | package spire.syntax 2 | 3 | import spire.algebra.{Field, CRing} 4 | 5 | object primitives: 6 | 7 | extension [A](n: Int) inline def as(using A: CRing[A]): A = inline n match 8 | case 0 => A.zero 9 | case 1 => A.one 10 | case n => A.fromInt(n) 11 | 12 | extension [A](n: Double) inline def as(using A: Field[A]): A = inline n match 13 | case 0 => A.zero 14 | case 1 => A.one 15 | case n => A.fromDouble(n) 16 | 17 | end primitives 18 | -------------------------------------------------------------------------------- /src/test/scala/spire/CforReturn.scala: -------------------------------------------------------------------------------- 1 | import spire.syntax.cfor._ 2 | 3 | def foo: Int = { 4 | cforRange(-10 to -1) { i => 5 | if i < 0 then return i 6 | } 7 | return 0 8 | } 9 | -------------------------------------------------------------------------------- /src/test/scala/spire/CforSpec.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | 3 | import language.implicitConversions 4 | 5 | import org.scalacheck.Properties 6 | import org.scalacheck._ 7 | import Prop._ 8 | import Gen.{posNum, choose} 9 | import syntax.cfor.{*, given} 10 | import collection.mutable.ListBuffer 11 | 12 | object CforSpec extends Properties("cfor") { 13 | 14 | def fillList[N](f: ListBuffer[N] => Unit): List[N] = { 15 | var b = ListBuffer.empty[N] 16 | f(b) 17 | b.toList 18 | } 19 | 20 | property("fillList with cfor") = forAll(posNum[Int]) { n => 21 | 22 | def fill(n: Int): List[Int] = fillList { b => 23 | cfor(1)(_ <= n, _ + 1)(b += _) 24 | } 25 | 26 | List.tabulate(n)(_ + 1) =? fill(n) 27 | } 28 | 29 | property("fillList with peek using to") = forAll(posNum[Int]) { n => 30 | List.range(0, n + 1) =? fillList { b => 0 to n peek (b += _) } 31 | } 32 | 33 | property("fillList with peek[Long] using to") = forAll(posNum[Long]) { n => 34 | List.range(0L, n + 1L) =? fillList { b => 0L to n peek (b += _) } 35 | } 36 | 37 | property("fillList with cforRange using to, by (positive)") = forAll(posNum[Int]) { n => 38 | 39 | def fill(n: Int): List[Int] = fillList { b => 40 | cforRange(0 to n by 1)(b += _) 41 | } 42 | 43 | List.range(0, n + 1, 1) =? fill(n) 44 | } 45 | 46 | property("fillList with cforRange[Long] using to, by (positive)") = forAll(posNum[Long]) { n => 47 | 48 | def fill(n: Long): List[Long] = fillList { b => 49 | cforRange(0L to n by 1)(b += _) 50 | } 51 | 52 | List.range(0L, n + 1L, 1L) =? fill(n) 53 | } 54 | 55 | property("fillList with cforRange using to, by (negative)") = forAll(posNum[Int]) { n => 56 | 57 | def fill(n: Int): List[Int] = fillList { b => 58 | cforRange(0 to -n by -1)(b += _) 59 | } 60 | 61 | List.range(0, -n - 1, -1) =? fill(n) 62 | } 63 | 64 | property("fillList with cforRange[Long] using to, by (negative)") = forAll(posNum[Long]) { n => 65 | 66 | def fill(n: Long): List[Long] = fillList { b => 67 | cforRange(0L to -n by -1)(b += _) 68 | } 69 | 70 | List.range(0L, -n - 1, -1L) =? fill(n) 71 | } 72 | 73 | property("fillList with cforRange using until, by (positive)") = forAll(posNum[Int]) { n => 74 | 75 | def fill(n: Int): List[Int] = fillList { b => 76 | cforRange(0 until n by 1)(b += _) 77 | } 78 | 79 | List.range(0, n, 1) =? fill(n) 80 | } 81 | 82 | property("fillList with cforRange[Long] using until, by (positive)") = forAll(posNum[Long]) { n => 83 | 84 | def fill(n: Long): List[Long] = fillList { b => 85 | cforRange(0L until n by 1)(b += _) 86 | } 87 | 88 | List.range(0L, n, 1L) =? fill(n) 89 | } 90 | 91 | property("fillList with cforRange using until, by (negative)") = forAll(posNum[Int]) { n => 92 | 93 | def fill(n: Int): List[Int] = fillList { b => 94 | cforRange(0 until -n by -1)(b += _) 95 | } 96 | 97 | List.range(0, -n, -1) =? fill(n) 98 | } 99 | 100 | property("fillList with cforRange[Long] using until, by (negative)") = forAll(posNum[Long]) { n => 101 | 102 | def fill(n: Long): List[Long] = fillList { b => 103 | cforRange(0L until -n by -1)(b += _) 104 | } 105 | 106 | List.range(0L, -n, -1L) =? fill(n) 107 | } 108 | 109 | property("fillList with cforRange using until") = forAll(posNum[Int]) { n => 110 | 111 | def fill(n: Int): List[Int] = fillList { b => 112 | cforRange(0 until n)(b += _) 113 | } 114 | 115 | List.range(0, n) =? fill(n) 116 | } 117 | 118 | property("fillList with cforRange[Long] using until") = forAll(posNum[Long]) { n => 119 | 120 | def fill(n: Long): List[Long] = fillList { b => 121 | cforRange(0L until n)(b += _) 122 | } 123 | 124 | List.range(0L, n) =? fill(n) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/test/scala/spire/GenericLiterals.scala: -------------------------------------------------------------------------------- 1 | package spire 2 | 3 | import scala.language.experimental.genericNumberLiterals 4 | 5 | import spire.syntax.literals.given 6 | import spire.algebra.{Field, CRing} 7 | 8 | import scala.annotation.experimental 9 | 10 | @experimental 11 | object GenericLiterals { 12 | 13 | // Field 14 | 15 | def zeroF[A: Field]: A = 0.0 // summon[Field[A]].zero 16 | def oneF[A: Field]: A = 1 // summon[Field[A]].one 17 | def twoF[A: Field]: A = 2 // summon[Field[A]].fromInt(2) 18 | def three[A: Field]: A = 3.0 // summon[Field[A]].fromDouble(3.0) 19 | def bigF[A: Field]: A = 37237283824892382 // summon[Field[A]].fromBigInt(BigInt(Array[Byte](0,-124,75,28,-62,-56,121,-34))) 20 | def huge[A: Field]: A = 1e1000 // summon[Field[A]].fromBigDecimal(BigDecimal("1E+1000")) 21 | 22 | // CRing 23 | 24 | def zero[A: CRing]: A = 0 // summon[CRing[A]].zero 25 | def one[A: CRing]: A = 1 // summon[CRing[A]].one 26 | def two[A: CRing]: A = 2 // summon[CRing[A]].fromInt(2) 27 | def hexI[A: CRing]: A = 0xCAFE // summon[CRing[A]].fromInt(51966) 28 | def hexB[A: CRing]: A = 0xCAFEBABE000000F // summon[CRing[A]].fromBigInt(BigInt(Array[Byte](12,-81,-21,-85,-32,0,0,15))) 29 | def big[A: CRing]: A = 37237283824892382 // summon[CRing[A]].fromBigInt(BigInt(Array[Byte](0,-124,75,28,-62,-56,121,-34))) 30 | } 31 | --------------------------------------------------------------------------------