From 045a03b4dc6d716c1c9635549451fa5cebaf4a8d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 30 Aug 2019 07:20:44 +1000 Subject: [PATCH 1/3] Cache Numeric.{zero,one} in provided type class instances --- src/library/scala/math/Numeric.scala | 57 ++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/library/scala/math/Numeric.scala b/src/library/scala/math/Numeric.scala index 937dd2da24da..93a2a271e101 100644 --- a/src/library/scala/math/Numeric.scala +++ b/src/library/scala/math/Numeric.scala @@ -44,7 +44,10 @@ object Numeric { def toFloat(x: BigInt): Float = x.floatValue def toDouble(x: BigInt): Double = x.doubleValue } - implicit object BigIntIsIntegral extends BigIntIsIntegral with Ordering.BigIntOrdering + implicit object BigIntIsIntegral extends BigIntIsIntegral with Ordering.BigIntOrdering { + override val zero: BigInt = super.zero + override val one: BigInt = super.one + } trait IntIsIntegral extends Integral[Int] { def plus(x: Int, y: Int): Int = x + y @@ -59,7 +62,10 @@ object Numeric { def toFloat(x: Int): Float = x.toFloat def toDouble(x: Int): Double = x.toDouble } - implicit object IntIsIntegral extends IntIsIntegral with Ordering.IntOrdering + implicit object IntIsIntegral extends IntIsIntegral with Ordering.IntOrdering { + override val zero: Int = super.zero + override val one: Int = super.one + } trait ShortIsIntegral extends Integral[Short] { def plus(x: Short, y: Short): Short = (x + y).toShort @@ -74,7 +80,10 @@ object Numeric { def toFloat(x: Short): Float = x.toFloat def toDouble(x: Short): Double = x.toDouble } - implicit object ShortIsIntegral extends ShortIsIntegral with Ordering.ShortOrdering + implicit object ShortIsIntegral extends ShortIsIntegral with Ordering.ShortOrdering { + override val zero: Short = super.zero + override val one: Short = super.one + } trait ByteIsIntegral extends Integral[Byte] { def plus(x: Byte, y: Byte): Byte = (x + y).toByte @@ -89,7 +98,10 @@ object Numeric { def toFloat(x: Byte): Float = x.toFloat def toDouble(x: Byte): Double = x.toDouble } - implicit object ByteIsIntegral extends ByteIsIntegral with Ordering.ByteOrdering + implicit object ByteIsIntegral extends ByteIsIntegral with Ordering.ByteOrdering { + override val zero: Byte = super.zero + override val one: Byte = super.one + } trait CharIsIntegral extends Integral[Char] { def plus(x: Char, y: Char): Char = (x + y).toChar @@ -104,7 +116,10 @@ object Numeric { def toFloat(x: Char): Float = x.toFloat def toDouble(x: Char): Double = x.toDouble } - implicit object CharIsIntegral extends CharIsIntegral with Ordering.CharOrdering + implicit object CharIsIntegral extends CharIsIntegral with Ordering.CharOrdering { + override val zero: Char = super.zero + override val one: Char = super.one + } trait LongIsIntegral extends Integral[Long] { def plus(x: Long, y: Long): Long = x + y @@ -119,7 +134,10 @@ object Numeric { def toFloat(x: Long): Float = x.toFloat def toDouble(x: Long): Double = x.toDouble } - implicit object LongIsIntegral extends LongIsIntegral with Ordering.LongOrdering + implicit object LongIsIntegral extends LongIsIntegral with Ordering.LongOrdering { + override val zero: Long = super.zero + override val one: Long = super.one + } trait FloatIsConflicted extends Numeric[Float] { def plus(x: Float, y: Float): Float = x + y @@ -141,8 +159,13 @@ object Numeric { def quot(x: Float, y: Float): Float = (BigDecimal(x) quot BigDecimal(y)).floatValue def rem(x: Float, y: Float): Float = (BigDecimal(x) remainder BigDecimal(y)).floatValue } - implicit object FloatIsFractional extends FloatIsFractional with Ordering.FloatOrdering + implicit object FloatIsFractional extends FloatIsFractional with Ordering.FloatOrdering { + override val zero: Float = super.zero + override val one: Float = super.one + } object FloatAsIfIntegral extends FloatAsIfIntegral with Ordering.FloatOrdering { + override val zero: Float = super.zero + override val one: Float = super.one } trait DoubleIsConflicted extends Numeric[Double] { @@ -188,11 +211,23 @@ object Numeric { // For Double and BigDecimal we offer implicit Fractional objects, but also one // which acts like an Integral type, which is useful in NumericRange. - implicit object BigDecimalIsFractional extends BigDecimalIsFractional with Ordering.BigDecimalOrdering - object BigDecimalAsIfIntegral extends BigDecimalAsIfIntegral with Ordering.BigDecimalOrdering + implicit object BigDecimalIsFractional extends BigDecimalIsFractional with Ordering.BigDecimalOrdering { + override val zero: BigDecimal = super.zero + override val one: BigDecimal = super.one + } + object BigDecimalAsIfIntegral extends BigDecimalAsIfIntegral with Ordering.BigDecimalOrdering { + override val zero: BigDecimal = super.zero + override val one: BigDecimal = super.one + } - implicit object DoubleIsFractional extends DoubleIsFractional with Ordering.DoubleOrdering - object DoubleAsIfIntegral extends DoubleAsIfIntegral with Ordering.DoubleOrdering + implicit object DoubleIsFractional extends DoubleIsFractional with Ordering.DoubleOrdering { + override val zero: Double = super.zero + override val one: Double = super.one + } + object DoubleAsIfIntegral extends DoubleAsIfIntegral with Ordering.DoubleOrdering { + override val zero: Double = super.zero + override val one: Double = super.one + } } trait Numeric[T] extends Ordering[T] { From 09419e84e776d7f81aa31295013654b75775b933 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 30 Aug 2019 11:15:53 +1000 Subject: [PATCH 2/3] Another approach, could we whitelist this from MiMa --- src/library/scala/math/Numeric.scala | 66 +++++++--------------------- 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/src/library/scala/math/Numeric.scala b/src/library/scala/math/Numeric.scala index 93a2a271e101..c1b776006017 100644 --- a/src/library/scala/math/Numeric.scala +++ b/src/library/scala/math/Numeric.scala @@ -44,10 +44,7 @@ object Numeric { def toFloat(x: BigInt): Float = x.floatValue def toDouble(x: BigInt): Double = x.doubleValue } - implicit object BigIntIsIntegral extends BigIntIsIntegral with Ordering.BigIntOrdering { - override val zero: BigInt = super.zero - override val one: BigInt = super.one - } + implicit object BigIntIsIntegral extends CachedNumeric[BigInt] with BigIntIsIntegral with Ordering.BigIntOrdering trait IntIsIntegral extends Integral[Int] { def plus(x: Int, y: Int): Int = x + y @@ -62,10 +59,7 @@ object Numeric { def toFloat(x: Int): Float = x.toFloat def toDouble(x: Int): Double = x.toDouble } - implicit object IntIsIntegral extends IntIsIntegral with Ordering.IntOrdering { - override val zero: Int = super.zero - override val one: Int = super.one - } + implicit object IntIsIntegral extends CachedNumeric[Int] with IntIsIntegral with Ordering.IntOrdering trait ShortIsIntegral extends Integral[Short] { def plus(x: Short, y: Short): Short = (x + y).toShort @@ -80,12 +74,9 @@ object Numeric { def toFloat(x: Short): Float = x.toFloat def toDouble(x: Short): Double = x.toDouble } - implicit object ShortIsIntegral extends ShortIsIntegral with Ordering.ShortOrdering { - override val zero: Short = super.zero - override val one: Short = super.one - } + implicit object ShortIsIntegral extends CachedNumeric[Short] with ShortIsIntegral with Ordering.ShortOrdering - trait ByteIsIntegral extends Integral[Byte] { + trait ByteIsIntegral extends CachedNumeric[Byte] with Integral[Byte] { def plus(x: Byte, y: Byte): Byte = (x + y).toByte def minus(x: Byte, y: Byte): Byte = (x - y).toByte def times(x: Byte, y: Byte): Byte = (x * y).toByte @@ -98,10 +89,7 @@ object Numeric { def toFloat(x: Byte): Float = x.toFloat def toDouble(x: Byte): Double = x.toDouble } - implicit object ByteIsIntegral extends ByteIsIntegral with Ordering.ByteOrdering { - override val zero: Byte = super.zero - override val one: Byte = super.one - } + implicit object ByteIsIntegral extends CachedNumeric[Byte] with ByteIsIntegral with Ordering.ByteOrdering trait CharIsIntegral extends Integral[Char] { def plus(x: Char, y: Char): Char = (x + y).toChar @@ -116,10 +104,7 @@ object Numeric { def toFloat(x: Char): Float = x.toFloat def toDouble(x: Char): Double = x.toDouble } - implicit object CharIsIntegral extends CharIsIntegral with Ordering.CharOrdering { - override val zero: Char = super.zero - override val one: Char = super.one - } + implicit object CharIsIntegral extends CachedNumeric[Char] with CharIsIntegral with Ordering.CharOrdering trait LongIsIntegral extends Integral[Long] { def plus(x: Long, y: Long): Long = x + y @@ -134,10 +119,7 @@ object Numeric { def toFloat(x: Long): Float = x.toFloat def toDouble(x: Long): Double = x.toDouble } - implicit object LongIsIntegral extends LongIsIntegral with Ordering.LongOrdering { - override val zero: Long = super.zero - override val one: Long = super.one - } + implicit object LongIsIntegral extends CachedNumeric[Long] with LongIsIntegral with Ordering.LongOrdering trait FloatIsConflicted extends Numeric[Float] { def plus(x: Float, y: Float): Float = x + y @@ -159,14 +141,8 @@ object Numeric { def quot(x: Float, y: Float): Float = (BigDecimal(x) quot BigDecimal(y)).floatValue def rem(x: Float, y: Float): Float = (BigDecimal(x) remainder BigDecimal(y)).floatValue } - implicit object FloatIsFractional extends FloatIsFractional with Ordering.FloatOrdering { - override val zero: Float = super.zero - override val one: Float = super.one - } - object FloatAsIfIntegral extends FloatAsIfIntegral with Ordering.FloatOrdering { - override val zero: Float = super.zero - override val one: Float = super.one - } + implicit object FloatIsFractional extends CachedNumeric[Float] with FloatIsFractional with Ordering.FloatOrdering + object FloatAsIfIntegral extends CachedNumeric[Float] with FloatAsIfIntegral with Ordering.FloatOrdering trait DoubleIsConflicted extends Numeric[Double] { def plus(x: Double, y: Double): Double = x + y @@ -211,22 +187,14 @@ object Numeric { // For Double and BigDecimal we offer implicit Fractional objects, but also one // which acts like an Integral type, which is useful in NumericRange. - implicit object BigDecimalIsFractional extends BigDecimalIsFractional with Ordering.BigDecimalOrdering { - override val zero: BigDecimal = super.zero - override val one: BigDecimal = super.one - } - object BigDecimalAsIfIntegral extends BigDecimalAsIfIntegral with Ordering.BigDecimalOrdering { - override val zero: BigDecimal = super.zero - override val one: BigDecimal = super.one - } - - implicit object DoubleIsFractional extends DoubleIsFractional with Ordering.DoubleOrdering { - override val zero: Double = super.zero - override val one: Double = super.one - } - object DoubleAsIfIntegral extends DoubleAsIfIntegral with Ordering.DoubleOrdering { - override val zero: Double = super.zero - override val one: Double = super.one + implicit object BigDecimalIsFractional extends CachedNumeric[BigDecimal] with BigDecimalIsFractional with Ordering.BigDecimalOrdering + object BigDecimalAsIfIntegral extends CachedNumeric[BigDecimal] with BigDecimalAsIfIntegral with Ordering.BigDecimalOrdering + + implicit object DoubleIsFractional extends CachedNumeric[Double] with DoubleIsFractional with Ordering.DoubleOrdering + object DoubleAsIfIntegral extends CachedNumeric[Double] with DoubleAsIfIntegral with Ordering.DoubleOrdering + private[scala] abstract class CachedNumeric[T] extends Numeric[T] { + override val zero: T = super.zero + override val one: T = super.one } } From e0f5f7abd74c6deac66daeb320a84a4aab48b178 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 30 Aug 2019 11:16:35 +1000 Subject: [PATCH 3/3] Optimize some primitive WrappedArray.{sum,product} --- .../collection/mutable/WrappedArray.scala | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 8640e1212df1..62d261a2f1e3 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -178,6 +178,30 @@ object WrappedArray { case that: ofInt => Arrays.equals(array, that.array) case _ => super.equals(that) } + override def sum[B >: Int](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.IntIsIntegral) { + var z = 0 + var i = 0 + val as = array + while (i < as.length) { + z += as(i) + i += 1 + } + z + } else { + super.sum[B] + } + override def product[B >: Int](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.IntIsIntegral) { + var z = 0 + var i = 0 + val as = array + while (i < as.length) { + z *= as(i) + i += 1 + } + z + } else { + super.sum[B] + } } final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable { @@ -190,6 +214,30 @@ object WrappedArray { case that: ofLong => Arrays.equals(array, that.array) case _ => super.equals(that) } + override def sum[B >: Long](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.LongIsIntegral) { + var z = 0L + var i = 0 + val as = array + while (i < as.length) { + z += as(i) + i += 1 + } + z + } else { + super.sum[B] + } + override def product[B >: Long](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.LongIsIntegral) { + var z = 0L + var i = 0 + val as = array + while (i < as.length) { + z *= as(i) + i += 1 + } + z + } else { + super.sum[B] + } } final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable { @@ -202,6 +250,30 @@ object WrappedArray { case that: ofFloat => Arrays.equals(array, that.array) case _ => super.equals(that) } + override def sum[B >: Float](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.FloatIsFractional) { + var z = 0f + var i = 0 + val as = array + while (i < as.length) { + z += as(i) + i += 1 + } + z + } else { + super.sum[B] + } + override def product[B >: Float](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.FloatIsFractional) { + var z = 0f + var i = 0 + val as = array + while (i < as.length) { + z *= as(i) + i += 1 + } + z + } else { + super.sum[B] + } } final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable { @@ -214,6 +286,30 @@ object WrappedArray { case that: ofDouble => Arrays.equals(array, that.array) case _ => super.equals(that) } + override def sum[B >: Double](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.DoubleIsFractional) { + var z = 0d + var i = 0 + val as = array + while (i < as.length) { + z += as(i) + i += 1 + } + z + } else { + super.sum[B] + } + override def product[B >: Double](implicit num: Numeric[B]): B = if (num eq scala.math.Numeric.DoubleIsFractional) { + var z = 0d + var i = 0 + val as = array + while (i < as.length) { + z *= as(i) + i += 1 + } + z + } else { + super.sum[B] + } } final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable {