Fast power is added

This commit is contained in:
zhelenskiy 2021-05-10 17:57:49 +03:00
parent f67cfcc9e6
commit 1716b7f5d1
3 changed files with 31 additions and 4 deletions

View File

@ -15,15 +15,13 @@ import space.kscience.kmath.operations.BigIntField
import space.kscience.kmath.operations.JBigIntegerField import space.kscience.kmath.operations.JBigIntegerField
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
private fun BigInt.pow(power: Int): BigInt = modPow(BigIntField.number(power), BigInt.ONE)
@State(Scope.Benchmark) @State(Scope.Benchmark)
internal class BigIntBenchmark { internal class BigIntBenchmark {
val kmNumber = BigIntField.number(Int.MAX_VALUE) val kmNumber = BigIntField.number(Int.MAX_VALUE)
val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE) val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE)
val largeKmNumber = BigIntField { number(11).pow(100_000) } val largeKmNumber = BigIntField { number(11).pow(100_000UL) }
val largeJvmNumber = JBigIntegerField { number(11).pow(100_000) } val largeJvmNumber = JBigIntegerField { number(11).pow(100_000) }
val bigExponent = 50_000 val bigExponent = 50_000
@ -59,7 +57,7 @@ internal class BigIntBenchmark {
@Benchmark @Benchmark
fun kmPower(blackhole: Blackhole) = BigIntField { fun kmPower(blackhole: Blackhole) = BigIntField {
blackhole.consume(kmNumber.pow(bigExponent)) blackhole.consume(kmNumber.pow(bigExponent.toULong()))
} }
@Benchmark @Benchmark

View File

@ -250,6 +250,21 @@ public interface Ring<T> : Group<T>, RingOperations<T> {
* neutral operation for multiplication * neutral operation for multiplication
*/ */
public val one: T public val one: T
public fun T.pow(exponent: ULong): T = when {
this == zero && exponent > 0UL -> zero
this == one -> this
else -> powWithoutOptimization(exponent)
}
private fun T.powWithoutOptimization(exponent: ULong): T = when (exponent) {
0UL -> one
1UL -> this
else -> {
val pre = powWithoutOptimization(exponent shr 1).let { it * it }
if (exponent and 1UL == 0UL) pre else pre * this
}
}
} }
/** /**

View File

@ -6,6 +6,7 @@
package space.kscience.kmath.operations package space.kscience.kmath.operations
import space.kscience.kmath.testutils.RingVerifier import space.kscience.kmath.testutils.RingVerifier
import kotlin.math.pow
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -21,6 +22,19 @@ internal class BigIntAlgebraTest {
assertEquals(res, 1_000_000.toBigInt()) assertEquals(res, 1_000_000.toBigInt())
} }
@Test
fun testKBigIntegerRingPow() {
BigIntField {
for (num in 0..5)
for (exponent in 0UL..10UL)
assertEquals(
num.toDouble().pow(exponent.toInt()).toLong().toBigInt(),
num.toBigInt().pow(exponent),
"$num ^ $exponent"
)
}
}
@Test @Test
fun testKBigIntegerRingSum_100_000_000__100_000_000() { fun testKBigIntegerRingSum_100_000_000__100_000_000() {
BigIntField { BigIntField {