From dc9ec54644c4d7b9675bfd9959ee2e1f84829152 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 14 May 2021 09:32:24 +0300 Subject: [PATCH] naming fix and doc update --- CHANGELOG.md | 1 + kmath-core/api/kmath-core.api | 3 ++- .../space/kscience/kmath/operations/BigInt.kt | 2 +- .../kmath/operations/algebraExtensions.kt | 22 +++++++++---------- .../kmath/operations/BigIntOperationsTest.kt | 14 +++++++----- .../kmath/operations/DoubleFieldTest.kt | 14 ++++++------ 6 files changed, 30 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 286be25e5..732cc87a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Extended operations for ND4J fields - Jupyter Notebook integration module (kmath-jupyter) - `@PerformancePitfall` annotation to mark possibly slow API +- BigInt operation performance improvement and fixes by @zhelenskiy (#328) ### Changed - Exponential operations merged with hyperbolic functions diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 14bc70a2a..7b09b668b 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -1020,7 +1020,7 @@ public final class space/kscience/kmath/operations/AlgebraExtensionsKt { public static final fun averageWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; public static final fun averageWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; public static final fun power (Lspace/kscience/kmath/operations/Field;Ljava/lang/Object;I)Ljava/lang/Object; - public static final fun power (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Object;I)Ljava/lang/Object; + public static final fun power-jXDDuk8 (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Object;I)Ljava/lang/Object; public static final fun sum (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Iterable;)Ljava/lang/Object; public static final fun sum (Lspace/kscience/kmath/operations/Ring;Lkotlin/sequences/Sequence;)Ljava/lang/Object; public static final fun sumWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; @@ -1050,6 +1050,7 @@ public final class space/kscience/kmath/operations/BigInt : java/lang/Comparable public final fun modPow (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; public final fun or (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; public final fun plus (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; + public final fun pow-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; public final fun rem (I)I public final fun rem (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; public final fun shl (I)Lspace/kscience/kmath/operations/BigInt; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 924ef07f4..ac53c4d5e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -98,7 +98,7 @@ public class BigInt internal constructor( else -> BigInt(sign, multiplyMagnitudeByUInt(magnitude, other)) } - public fun pow(exponent: UInt): BigInt = BigIntField.power(this@BigInt, exponent) + public fun pow(exponent: UInt): BigInt = BigIntField.power(this, exponent) public operator fun times(other: Int): BigInt = when { other > 0 -> this * kotlin.math.abs(other).toUInt() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt index 830c504f3..422b1ae1a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt @@ -97,21 +97,21 @@ public fun Sequence.averageWith(space: S): T where S : Ring, S : Sc //TODO optimized power operation /** - * Raises [arg] to the non-negative integer power [power]. + * Raises [arg] to the non-negative integer power [exponent]. * * Special case: 0 ^ 0 is 1. * * @receiver the algebra to provide multiplication. * @param arg the base. - * @param power the exponent. + * @param exponent the exponent. * @return the base raised to the power. * @author Evgeniy Zhelenskiy */ -public fun Ring.power(arg: T, power: UInt): T = when { - arg == zero && power > 0U -> zero +public fun Ring.power(arg: T, exponent: UInt): T = when { + arg == zero && exponent > 0U -> zero arg == one -> arg - arg == -one -> powWithoutOptimization(arg, power % 2U) - else -> powWithoutOptimization(arg, power) + arg == -one -> powWithoutOptimization(arg, exponent % 2U) + else -> powWithoutOptimization(arg, exponent) } private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { @@ -125,17 +125,17 @@ private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = whe /** - * Raises [arg] to the integer power [power]. + * Raises [arg] to the integer power [exponent]. * * Special case: 0 ^ 0 is 1. * * @receiver the algebra to provide multiplication and division. * @param arg the base. - * @param power the exponent. + * @param exponent the exponent. * @return the base raised to the power. * @author Iaroslav Postovalov, Evgeniy Zhelenskiy */ -public fun Field.power(arg: T, power: Int): T = when { - power < 0 -> one / (this as Ring).power(arg, if (power == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-power).toUInt()) - else -> (this as Ring).power(arg, power.toUInt()) +public fun Field.power(arg: T, exponent: Int): T = when { + exponent < 0 -> one / (this as Ring).power(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) + else -> (this as Ring).power(arg, exponent.toUInt()) } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt index 9f35f7a69..26d6af224 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt @@ -7,7 +7,10 @@ package space.kscience.kmath.operations import kotlin.random.Random import kotlin.random.nextUInt -import kotlin.test.* +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertFalse @kotlin.ExperimentalUnsignedTypes class BigIntOperationsTest { @@ -153,14 +156,13 @@ class BigIntOperationsTest { @Test fun testKaratsuba() { + val random = Random(2222) val x = uintArrayOf(12U, 345U) val y = uintArrayOf(6U, 789U) assertContentEquals(BigInt.naiveMultiplyMagnitudes(x, y), BigInt.karatsubaMultiplyMagnitudes(x, y)) - repeat(1000) { - val x1 = UIntArray(Random.nextInt(100, 1000)) { Random.nextUInt() } - val y1 = UIntArray(Random.nextInt(100, 1000)) { Random.nextUInt() } - assertContentEquals(BigInt.naiveMultiplyMagnitudes(x1, y1), BigInt.karatsubaMultiplyMagnitudes(x1, y1)) - } + val x1 = UIntArray(Random.nextInt(100, 1000)) { random.nextUInt() } + val y1 = UIntArray(Random.nextInt(100, 1000)) { random.nextUInt() } + assertContentEquals(BigInt.naiveMultiplyMagnitudes(x1, y1), BigInt.karatsubaMultiplyMagnitudes(x1, y1)) } @Test diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt index 7e689d079..76171fedd 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt @@ -22,12 +22,12 @@ internal class DoubleFieldTest { @Test fun testPow() = DoubleField { val num = 5 * one - assertEquals(5.0, power(num, 1)) - assertEquals(25.0, power(num, 2)) - assertEquals(1.0, power(num, 0)) - assertEquals(0.2, power(num, -1)) - assertEquals(0.04, power(num, -2)) - assertEquals(0.0, power(num, Int.MIN_VALUE)) - assertEquals(1.0, power(zero, 0)) + assertEquals(5.0, power(num, 1), 0.01) + assertEquals(25.0, power(num, 2), 0.01) + assertEquals(1.0, power(num, 0), 0.01) + assertEquals(0.2, power(num, -1), 0.01) + assertEquals(0.04, power(num, -2), 0.01) + assertEquals(0.0, power(num, Int.MIN_VALUE), 0.01) + assertEquals(1.0, power(zero, 0), 0.01) } }