forked from kscience/kmath
BigInt refactoring
This commit is contained in:
parent
85ad44ac9b
commit
fbe7363cde
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("scientifik.publish") version "0.4.2" apply false
|
id("scientifik.publish") version "0.4.2" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
val kmathVersion by extra("0.1.4-dev-3")
|
val kmathVersion by extra("0.1.4-dev-4")
|
||||||
|
|
||||||
val bintrayRepo by extra("scientifik")
|
val bintrayRepo by extra("scientifik")
|
||||||
val githubProject by extra("kmath")
|
val githubProject by extra("kmath")
|
||||||
|
@ -1,49 +1,45 @@
|
|||||||
package scientifik.kmath.operations
|
package scientifik.kmath.operations
|
||||||
|
|
||||||
|
import scientifik.kmath.operations.BigInt.Companion.BASE
|
||||||
|
import scientifik.kmath.operations.BigInt.Companion.BASE_SIZE
|
||||||
import kotlin.math.log2
|
import kotlin.math.log2
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.sign
|
import kotlin.math.sign
|
||||||
|
|
||||||
/*
|
|
||||||
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
|
|
||||||
* Initial version from https://github.com/robdrynkin/kotlin-big-integer
|
|
||||||
*/
|
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
typealias Magnitude = UIntArray
|
typealias Magnitude = UIntArray
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
typealias TBase = ULong
|
typealias TBase = ULong
|
||||||
|
|
||||||
object KBigIntegerRing: Ring<KBigInteger> {
|
/**
|
||||||
override val zero: KBigInteger = KBigInteger.ZERO
|
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
|
||||||
override val one: KBigInteger = KBigInteger.ONE
|
*
|
||||||
|
* @author Robert Drynkin (https://github.com/robdrynkin) and Peter Klimai (https://github.com/pklimai)
|
||||||
|
*/
|
||||||
|
object BigIntField : Field<BigInt> {
|
||||||
|
override val zero: BigInt = BigInt.ZERO
|
||||||
|
override val one: BigInt = BigInt.ONE
|
||||||
|
|
||||||
override fun add(a: KBigInteger, b: KBigInteger): KBigInteger = a.plus(b)
|
override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b)
|
||||||
|
|
||||||
override fun multiply(a: KBigInteger, k: Number): KBigInteger = a.times(k.toLong())
|
override fun multiply(a: BigInt, k: Number): BigInt = a.times(k.toLong())
|
||||||
|
|
||||||
override fun multiply(a: KBigInteger, b: KBigInteger): KBigInteger = a.times(b)
|
override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b)
|
||||||
|
|
||||||
operator fun String.unaryPlus(): KBigInteger = this.toKBigInteger()!!
|
operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer")
|
||||||
|
|
||||||
operator fun String.unaryMinus(): KBigInteger = -this.toKBigInteger()!!
|
operator fun String.unaryMinus(): BigInt =
|
||||||
|
-(this.parseBigInteger() ?: error("Can't parse $this as big integer"))
|
||||||
|
|
||||||
|
override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
class BigInt internal constructor(
|
||||||
class KBigInteger internal constructor(
|
private val sign: Byte,
|
||||||
private val sign: Byte = 0,
|
private val magnitude: Magnitude
|
||||||
private val magnitude: Magnitude = Magnitude(0)
|
) : Comparable<BigInt> {
|
||||||
): Comparable<KBigInteger> {
|
|
||||||
|
|
||||||
constructor(x: Int) : this(x.sign.toByte(), uintArrayOf(kotlin.math.abs(x).toUInt()))
|
override fun compareTo(other: BigInt): Int {
|
||||||
|
|
||||||
constructor(x: Long) : this(x.sign.toByte(), stripLeadingZeros(uintArrayOf(
|
|
||||||
(kotlin.math.abs(x).toULong() and BASE).toUInt(),
|
|
||||||
((kotlin.math.abs(x).toULong() shr BASE_SIZE) and BASE).toUInt())))
|
|
||||||
|
|
||||||
override fun compareTo(other: KBigInteger): Int {
|
|
||||||
return when {
|
return when {
|
||||||
(this.sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0
|
(this.sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0
|
||||||
this.sign < other.sign -> -1
|
this.sign < other.sign -> -1
|
||||||
@ -53,85 +49,87 @@ class KBigInteger internal constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other is KBigInteger) {
|
if (other is BigInt) {
|
||||||
return this.compareTo(other) == 0
|
return this.compareTo(other) == 0
|
||||||
}
|
} else error("Can't compare KBigInteger to a different type")
|
||||||
else error("Can't compare KBigInteger to a different type")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return magnitude.hashCode() + this.sign
|
return magnitude.hashCode() + this.sign
|
||||||
}
|
}
|
||||||
|
|
||||||
fun abs(): KBigInteger = if (sign == 0.toByte()) this else KBigInteger(1, magnitude)
|
fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude)
|
||||||
|
|
||||||
operator fun unaryMinus(): KBigInteger {
|
operator fun unaryMinus(): BigInt {
|
||||||
return if (this.sign == 0.toByte()) this else KBigInteger((-this.sign).toByte(), this.magnitude)
|
return if (this.sign == 0.toByte()) this else BigInt((-this.sign).toByte(), this.magnitude)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(b: KBigInteger): KBigInteger {
|
operator fun plus(b: BigInt): BigInt {
|
||||||
return when {
|
return when {
|
||||||
b.sign == 0.toByte() -> this
|
b.sign == 0.toByte() -> this
|
||||||
this.sign == 0.toByte() -> b
|
this.sign == 0.toByte() -> b
|
||||||
this == -b -> ZERO
|
this == -b -> ZERO
|
||||||
this.sign == b.sign -> KBigInteger(this.sign, addMagnitudes(this.magnitude, b.magnitude))
|
this.sign == b.sign -> BigInt(this.sign, addMagnitudes(this.magnitude, b.magnitude))
|
||||||
else -> {
|
else -> {
|
||||||
val comp: Int = compareMagnitudes(this.magnitude, b.magnitude)
|
val comp: Int = compareMagnitudes(this.magnitude, b.magnitude)
|
||||||
|
|
||||||
if (comp == 1) {
|
if (comp == 1) {
|
||||||
KBigInteger(this.sign, subtractMagnitudes(this.magnitude, b.magnitude))
|
BigInt(this.sign, subtractMagnitudes(this.magnitude, b.magnitude))
|
||||||
} else {
|
} else {
|
||||||
KBigInteger((-this.sign).toByte(), subtractMagnitudes(b.magnitude, this.magnitude))
|
BigInt((-this.sign).toByte(), subtractMagnitudes(b.magnitude, this.magnitude))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun minus(b: KBigInteger): KBigInteger {
|
operator fun minus(b: BigInt): BigInt {
|
||||||
return this + (-b)
|
return this + (-b)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun times(b: KBigInteger): KBigInteger {
|
operator fun times(b: BigInt): BigInt {
|
||||||
return when {
|
return when {
|
||||||
this.sign == 0.toByte() -> ZERO
|
this.sign == 0.toByte() -> ZERO
|
||||||
b.sign == 0.toByte() -> ZERO
|
b.sign == 0.toByte() -> ZERO
|
||||||
// TODO: Karatsuba
|
// TODO: Karatsuba
|
||||||
else -> KBigInteger((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude))
|
else -> BigInt((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun times(other: UInt): KBigInteger {
|
operator fun times(other: UInt): BigInt {
|
||||||
return when {
|
return when {
|
||||||
this.sign == 0.toByte() -> ZERO
|
this.sign == 0.toByte() -> ZERO
|
||||||
other == 0U -> ZERO
|
other == 0U -> ZERO
|
||||||
else -> KBigInteger(this.sign, multiplyMagnitudeByUInt(this.magnitude, other))
|
else -> BigInt(this.sign, multiplyMagnitudeByUInt(this.magnitude, other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun times(other: Int): KBigInteger {
|
operator fun times(other: Int): BigInt {
|
||||||
return if (other > 0)
|
return if (other > 0)
|
||||||
this * kotlin.math.abs(other).toUInt()
|
this * kotlin.math.abs(other).toUInt()
|
||||||
else
|
else
|
||||||
-this * kotlin.math.abs(other).toUInt()
|
-this * kotlin.math.abs(other).toUInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun div(other: UInt): KBigInteger {
|
operator fun div(other: UInt): BigInt {
|
||||||
return KBigInteger(this.sign, divideMagnitudeByUInt(this.magnitude, other))
|
return BigInt(this.sign, divideMagnitudeByUInt(this.magnitude, other))
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun div(other: Int): KBigInteger {
|
operator fun div(other: Int): BigInt {
|
||||||
return KBigInteger((this.sign * other.sign).toByte(),
|
return BigInt(
|
||||||
divideMagnitudeByUInt(this.magnitude, kotlin.math.abs(other).toUInt()))
|
(this.sign * other.sign).toByte(),
|
||||||
|
divideMagnitudeByUInt(this.magnitude, kotlin.math.abs(other).toUInt())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun division(other: KBigInteger): Pair<KBigInteger, KBigInteger> {
|
private fun division(other: BigInt): Pair<BigInt, BigInt> {
|
||||||
// Long division algorithm:
|
// Long division algorithm:
|
||||||
// https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder
|
// https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder
|
||||||
// TODO: Implement more effective algorithm
|
// TODO: Implement more effective algorithm
|
||||||
var q: KBigInteger = ZERO
|
var q: BigInt = ZERO
|
||||||
var r: KBigInteger = ZERO
|
var r: BigInt = ZERO
|
||||||
|
|
||||||
val bitSize = (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.last().toFloat() + 1)).toInt()
|
val bitSize =
|
||||||
|
(BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt()
|
||||||
for (i in bitSize downTo 0) {
|
for (i in bitSize downTo 0) {
|
||||||
r = r shl 1
|
r = r shl 1
|
||||||
r = r or ((abs(this) shr i) and ONE)
|
r = r or ((abs(this) shr i) and ONE)
|
||||||
@ -141,21 +139,21 @@ class KBigInteger internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(KBigInteger((this.sign * other.sign).toByte(), q.magnitude), r)
|
return Pair(BigInt((this.sign * other.sign).toByte(), q.magnitude), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun div(other: KBigInteger): KBigInteger {
|
operator fun div(other: BigInt): BigInt {
|
||||||
return this.division(other).first
|
return this.division(other).first
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun shl(i: Int): KBigInteger {
|
infix fun shl(i: Int): BigInt {
|
||||||
if (this == ZERO) return ZERO
|
if (this == ZERO) return ZERO
|
||||||
if (i == 0) return this
|
if (i == 0) return this
|
||||||
|
|
||||||
val fullShifts = i / BASE_SIZE + 1
|
val fullShifts = i / BASE_SIZE + 1
|
||||||
val relShift = i % BASE_SIZE
|
val relShift = i % BASE_SIZE
|
||||||
val shiftLeft = {x: UInt -> if (relShift >= 32) 0U else x shl relShift}
|
val shiftLeft = { x: UInt -> if (relShift >= 32) 0U else x shl relShift }
|
||||||
val shiftRight = {x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shr (BASE_SIZE - relShift)}
|
val shiftRight = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shr (BASE_SIZE - relShift) }
|
||||||
|
|
||||||
val newMagnitude: Magnitude = Magnitude(this.magnitude.size + fullShifts)
|
val newMagnitude: Magnitude = Magnitude(this.magnitude.size + fullShifts)
|
||||||
|
|
||||||
@ -168,17 +166,17 @@ class KBigInteger internal constructor(
|
|||||||
|
|
||||||
newMagnitude[this.magnitude.size + fullShifts - 1] = shiftRight(this.magnitude.last())
|
newMagnitude[this.magnitude.size + fullShifts - 1] = shiftRight(this.magnitude.last())
|
||||||
|
|
||||||
return KBigInteger(this.sign, stripLeadingZeros(newMagnitude))
|
return BigInt(this.sign, stripLeadingZeros(newMagnitude))
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun shr(i: Int): KBigInteger {
|
infix fun shr(i: Int): BigInt {
|
||||||
if (this == ZERO) return ZERO
|
if (this == ZERO) return ZERO
|
||||||
if (i == 0) return this
|
if (i == 0) return this
|
||||||
|
|
||||||
val fullShifts = i / BASE_SIZE
|
val fullShifts = i / BASE_SIZE
|
||||||
val relShift = i % BASE_SIZE
|
val relShift = i % BASE_SIZE
|
||||||
val shiftRight = {x: UInt -> if (relShift >= 32) 0U else x shr relShift}
|
val shiftRight = { x: UInt -> if (relShift >= 32) 0U else x shr relShift }
|
||||||
val shiftLeft = {x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shl (BASE_SIZE - relShift)}
|
val shiftLeft = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shl (BASE_SIZE - relShift) }
|
||||||
if (this.magnitude.size - fullShifts <= 0) {
|
if (this.magnitude.size - fullShifts <= 0) {
|
||||||
return ZERO
|
return ZERO
|
||||||
}
|
}
|
||||||
@ -191,10 +189,10 @@ class KBigInteger internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return KBigInteger(this.sign, stripLeadingZeros(newMagnitude))
|
return BigInt(this.sign, stripLeadingZeros(newMagnitude))
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun or(other: KBigInteger): KBigInteger {
|
infix fun or(other: BigInt): BigInt {
|
||||||
if (this == ZERO) return other;
|
if (this == ZERO) return other;
|
||||||
if (other == ZERO) return this;
|
if (other == ZERO) return this;
|
||||||
val resSize = max(this.magnitude.size, other.magnitude.size)
|
val resSize = max(this.magnitude.size, other.magnitude.size)
|
||||||
@ -207,17 +205,17 @@ class KBigInteger internal constructor(
|
|||||||
newMagnitude[i] = newMagnitude[i] or other.magnitude[i]
|
newMagnitude[i] = newMagnitude[i] or other.magnitude[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return KBigInteger(1, stripLeadingZeros(newMagnitude))
|
return BigInt(1, stripLeadingZeros(newMagnitude))
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun and(other: KBigInteger): KBigInteger {
|
infix fun and(other: BigInt): BigInt {
|
||||||
if ((this == ZERO) or (other == ZERO)) return ZERO;
|
if ((this == ZERO) or (other == ZERO)) return ZERO;
|
||||||
val resSize = min(this.magnitude.size, other.magnitude.size)
|
val resSize = min(this.magnitude.size, other.magnitude.size)
|
||||||
val newMagnitude: Magnitude = Magnitude(resSize)
|
val newMagnitude: Magnitude = Magnitude(resSize)
|
||||||
for (i in 0 until resSize) {
|
for (i in 0 until resSize) {
|
||||||
newMagnitude[i] = this.magnitude[i] and other.magnitude[i]
|
newMagnitude[i] = this.magnitude[i] and other.magnitude[i]
|
||||||
}
|
}
|
||||||
return KBigInteger(1, stripLeadingZeros(newMagnitude))
|
return BigInt(1, stripLeadingZeros(newMagnitude))
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun rem(other: Int): Int {
|
operator fun rem(other: Int): Int {
|
||||||
@ -225,11 +223,11 @@ class KBigInteger internal constructor(
|
|||||||
return if (res == ZERO) 0 else res.sign * res.magnitude[0].toInt()
|
return if (res == ZERO) 0 else res.sign * res.magnitude[0].toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun rem(other: KBigInteger): KBigInteger {
|
operator fun rem(other: BigInt): BigInt {
|
||||||
return this - (this / other) * other
|
return this - (this / other) * other
|
||||||
}
|
}
|
||||||
|
|
||||||
fun modPow(exponent: KBigInteger, m: KBigInteger): KBigInteger {
|
fun modPow(exponent: BigInt, m: BigInt): BigInt {
|
||||||
return when {
|
return when {
|
||||||
exponent == ZERO -> ONE
|
exponent == ZERO -> ONE
|
||||||
exponent % 2 == 1 -> (this * modPow(exponent - ONE, m)) % m
|
exponent % 2 == 1 -> (this * modPow(exponent - ONE, m)) % m
|
||||||
@ -263,29 +261,15 @@ class KBigInteger internal constructor(
|
|||||||
companion object {
|
companion object {
|
||||||
const val BASE = 0xffffffffUL
|
const val BASE = 0xffffffffUL
|
||||||
const val BASE_SIZE: Int = 32
|
const val BASE_SIZE: Int = 32
|
||||||
val ZERO: KBigInteger = KBigInteger()
|
val ZERO: BigInt = BigInt(0, uintArrayOf())
|
||||||
val ONE: KBigInteger = KBigInteger(1)
|
val ONE: BigInt = BigInt(1, uintArrayOf(1u))
|
||||||
|
|
||||||
private val hexMapping: HashMap<UInt, String> =
|
private val hexMapping: HashMap<UInt, String> = hashMapOf(
|
||||||
hashMapOf(
|
0U to "0", 1U to "1", 2U to "2", 3U to "3",
|
||||||
0U to "0", 1U to "1", 2U to "2", 3U to "3",
|
4U to "4", 5U to "5", 6U to "6", 7U to "7",
|
||||||
4U to "4", 5U to "5", 6U to "6", 7U to "7",
|
8U to "8", 9U to "9", 10U to "a", 11U to "b",
|
||||||
8U to "8", 9U to "9", 10U to "a", 11U to "b",
|
12U to "c", 13U to "d", 14U to "e", 15U to "f"
|
||||||
12U to "c", 13U to "d", 14U to "e", 15U to "f"
|
)
|
||||||
)
|
|
||||||
|
|
||||||
internal fun stripLeadingZeros(mag: Magnitude): Magnitude {
|
|
||||||
if (mag.isEmpty() || mag.last() != 0U) {
|
|
||||||
return mag
|
|
||||||
}
|
|
||||||
var resSize: Int = mag.size - 1
|
|
||||||
while (mag[resSize] == 0U) {
|
|
||||||
if (resSize == 0)
|
|
||||||
break
|
|
||||||
resSize -= 1
|
|
||||||
}
|
|
||||||
return mag.sliceArray(IntRange(0, resSize))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compareMagnitudes(mag1: Magnitude, mag2: Magnitude): Int {
|
private fun compareMagnitudes(mag1: Magnitude, mag2: Magnitude): Int {
|
||||||
when {
|
when {
|
||||||
@ -329,8 +313,8 @@ class KBigInteger internal constructor(
|
|||||||
|
|
||||||
for (i in 0 until resultLength) {
|
for (i in 0 until resultLength) {
|
||||||
var res: Long =
|
var res: Long =
|
||||||
if (i < mag2.size) mag1[i].toLong() - mag2[i].toLong() - carry
|
if (i < mag2.size) mag1[i].toLong() - mag2[i].toLong() - carry
|
||||||
else mag1[i].toLong() - carry
|
else mag1[i].toLong() - carry
|
||||||
|
|
||||||
carry = if (res < 0) 1 else 0
|
carry = if (res < 0) 1 else 0
|
||||||
res += carry * (BASE + 1UL).toLong()
|
res += carry * (BASE + 1UL).toLong()
|
||||||
@ -390,33 +374,76 @@ class KBigInteger internal constructor(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
fun abs(x: KBigInteger): KBigInteger = x.abs()
|
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
private fun stripLeadingZeros(mag: Magnitude): Magnitude {
|
||||||
// Can't put it as constructor in class due to platform declaration clash with KBigInteger(Int)
|
if (mag.isEmpty() || mag.last() != 0U) {
|
||||||
fun KBigInteger(x: UInt): KBigInteger
|
return mag
|
||||||
= KBigInteger(1, uintArrayOf(x))
|
}
|
||||||
|
var resSize: Int = mag.size - 1
|
||||||
|
while (mag[resSize] == 0U) {
|
||||||
|
if (resSize == 0)
|
||||||
|
break
|
||||||
|
resSize -= 1
|
||||||
|
}
|
||||||
|
return mag.sliceArray(IntRange(0, resSize))
|
||||||
|
}
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
fun abs(x: BigInt): BigInt = x.abs()
|
||||||
// Can't put it as constructor in class due to platform declaration clash with KBigInteger(Long)
|
|
||||||
fun KBigInteger(x: ULong): KBigInteger
|
/**
|
||||||
= KBigInteger(1,
|
* Convert this [Int] to [BigInt]
|
||||||
KBigInteger.stripLeadingZeros(uintArrayOf(
|
*/
|
||||||
(x and KBigInteger.BASE).toUInt(),
|
fun Int.toBigInt() = BigInt(sign.toByte(), uintArrayOf(kotlin.math.abs(this).toUInt()))
|
||||||
((x shr KBigInteger.BASE_SIZE) and KBigInteger.BASE).toUInt())
|
|
||||||
)
|
/**
|
||||||
|
* Convert this [Long] to [BigInt]
|
||||||
|
*/
|
||||||
|
fun Long.toBigInt() = BigInt(
|
||||||
|
sign.toByte(), stripLeadingZeros(
|
||||||
|
uintArrayOf(
|
||||||
|
(kotlin.math.abs(this).toULong() and BASE).toUInt(),
|
||||||
|
((kotlin.math.abs(this).toULong() shr BASE_SIZE) and BASE).toUInt()
|
||||||
)
|
)
|
||||||
|
)
|
||||||
val hexChToInt = hashMapOf(
|
|
||||||
'0' to 0, '1' to 1, '2' to 2, '3' to 3,
|
|
||||||
'4' to 4, '5' to 5, '6' to 6, '7' to 7,
|
|
||||||
'8' to 8, '9' to 9, 'A' to 10, 'B' to 11,
|
|
||||||
'C' to 12, 'D' to 13, 'E' to 14, 'F' to 15
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns None if a valid number can not be read from a string
|
/**
|
||||||
fun String.toKBigInteger(): KBigInteger? {
|
* Convert UInt to [BigInt]
|
||||||
|
*/
|
||||||
|
fun UInt.toBigInt() = BigInt(1, uintArrayOf(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert ULong to [BigInt]
|
||||||
|
*/
|
||||||
|
fun ULong.toBigInt() = BigInt(
|
||||||
|
1,
|
||||||
|
stripLeadingZeros(
|
||||||
|
uintArrayOf(
|
||||||
|
(this and BigInt.BASE).toUInt(),
|
||||||
|
((this shr BigInt.BASE_SIZE) and BigInt.BASE).toUInt()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a [BigInt] with this array of magnitudes with protective copy
|
||||||
|
*/
|
||||||
|
fun UIntArray.toBigInt(sign: Byte): BigInt {
|
||||||
|
if (sign == 0.toByte() && isNotEmpty()) error("")
|
||||||
|
return BigInt(sign, this.copyOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
val hexChToInt = hashMapOf(
|
||||||
|
'0' to 0, '1' to 1, '2' to 2, '3' to 3,
|
||||||
|
'4' to 4, '5' to 5, '6' to 6, '7' to 7,
|
||||||
|
'8' to 8, '9' to 9, 'A' to 10, 'B' to 11,
|
||||||
|
'C' to 12, 'D' to 13, 'E' to 14, 'F' to 15
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns null if a valid number can not be read from a string
|
||||||
|
*/
|
||||||
|
fun String.parseBigInteger(): BigInt? {
|
||||||
val sign: Int
|
val sign: Int
|
||||||
val sPositive: String
|
val sPositive: String
|
||||||
when {
|
when {
|
||||||
@ -433,27 +460,25 @@ fun String.toKBigInteger(): KBigInteger? {
|
|||||||
sign = +1
|
sign = +1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var res = KBigInteger.ZERO
|
var res = BigInt.ZERO
|
||||||
var digitValue = KBigInteger.ONE
|
var digitValue = BigInt.ONE
|
||||||
val sPositiveUpper = sPositive.toUpperCase()
|
val sPositiveUpper = sPositive.toUpperCase()
|
||||||
if (sPositiveUpper.startsWith("0X")) { // hex representation
|
if (sPositiveUpper.startsWith("0X")) { // hex representation
|
||||||
val sHex = sPositiveUpper.substring(2)
|
val sHex = sPositiveUpper.substring(2)
|
||||||
for (ch in sHex.reversed()) {
|
for (ch in sHex.reversed()) {
|
||||||
if (ch == '_') continue
|
if (ch == '_') continue
|
||||||
res += digitValue * (hexChToInt[ch] ?: return null)
|
res += digitValue * (hexChToInt[ch] ?: return null)
|
||||||
digitValue *= KBigInteger(16)
|
digitValue *= 16.toBigInt()
|
||||||
}
|
}
|
||||||
}
|
} else { // decimal representation
|
||||||
else { // decimal representation
|
for (ch in sPositiveUpper.reversed()) {
|
||||||
val sDecimal = sPositiveUpper
|
|
||||||
for (ch in sDecimal.reversed()) {
|
|
||||||
if (ch == '_') continue
|
if (ch == '_') continue
|
||||||
if (ch !in '0'..'9') {
|
if (ch !in '0'..'9') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
res += digitValue * (ch.toInt() - '0'.toInt())
|
res += digitValue * (ch.toInt() - '0'.toInt())
|
||||||
digitValue *= KBigInteger(10)
|
digitValue *= 10.toBigInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res * sign
|
return res * sign
|
||||||
}
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package scientifik.kmath.operations
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class BigIntAlgebraTest {
|
||||||
|
@Test
|
||||||
|
fun testKBigIntegerRingSum() {
|
||||||
|
val res = BigIntField {
|
||||||
|
1_000L.toBigInt() * 1_000L.toBigInt()
|
||||||
|
}
|
||||||
|
assertEquals(res, 1_000_000.toBigInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testKBigIntegerRingSum_100_000_000__100_000_000() {
|
||||||
|
BigIntField {
|
||||||
|
val sum = +"100_000_000" + +"100_000_000"
|
||||||
|
assertEquals(sum, "200_000_000".parseBigInteger())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_mul_3__4() {
|
||||||
|
BigIntField {
|
||||||
|
val prod = +"0x3000_0000_0000" * +"0x4000_0000_0000_0000_0000"
|
||||||
|
assertEquals(prod, "0xc00_0000_0000_0000_0000_0000_0000_0000".parseBigInteger())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_div_big_1() {
|
||||||
|
BigIntField {
|
||||||
|
val res = +"1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000" /
|
||||||
|
+"555_000_444_000_333_000_222_000_111_000_999_001"
|
||||||
|
assertEquals(res, +"1801800360360432432518919022699")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_rem_big_1() {
|
||||||
|
BigIntField {
|
||||||
|
val res = +"1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000" %
|
||||||
|
+"555_000_444_000_333_000_222_000_111_000_999_001"
|
||||||
|
assertEquals(res, +"324121220440768000291647788404676301")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
package scientifik.kmath.operations
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class BigIntConstructorTest {
|
||||||
|
@Test
|
||||||
|
fun testConstructorZero() {
|
||||||
|
assertEquals(0.toBigInt(), uintArrayOf().toBigInt(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstructor8() {
|
||||||
|
assertEquals(
|
||||||
|
8.toBigInt(),
|
||||||
|
uintArrayOf(8U).toBigInt(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstructor_0xffffffffaL() {
|
||||||
|
val x = -0xffffffffaL.toBigInt()
|
||||||
|
val y = uintArrayOf(0xfffffffaU, 0xfU).toBigInt(-1)
|
||||||
|
assertEquals(x, y)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package scientifik.kmath.operations
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@kotlin.ExperimentalUnsignedTypes
|
||||||
|
class BigIntConversionsTest {
|
||||||
|
@Test
|
||||||
|
fun testToString0x10() {
|
||||||
|
val x = 0x10.toBigInt()
|
||||||
|
assertEquals("0x10", x.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToString0x17ffffffd() {
|
||||||
|
val x = 0x17ffffffdL.toBigInt()
|
||||||
|
assertEquals("0x17ffffffd", x.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToString_0x17ead2ffffd() {
|
||||||
|
val x = -0x17ead2ffffdL.toBigInt()
|
||||||
|
assertEquals("-0x17ead2ffffd", x.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToString_0x17ead2ffffd11223344() {
|
||||||
|
val x = uintArrayOf(0x11223344U, 0xad2ffffdU, 0x17eU).toBigInt(-1)
|
||||||
|
assertEquals("-0x17ead2ffffd11223344", x.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFromString_0x17ead2ffffd11223344() {
|
||||||
|
val x = "0x17ead2ffffd11223344".parseBigInteger()
|
||||||
|
assertEquals("0x17ead2ffffd11223344", x.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFromString_7059135710711894913860() {
|
||||||
|
val x = "-7059135710711894913860".parseBigInteger()
|
||||||
|
assertEquals("-0x17ead2ffffd11223344", x.toString())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,381 @@
|
|||||||
|
package scientifik.kmath.operations
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@kotlin.ExperimentalUnsignedTypes
|
||||||
|
class BigIntOperationsTest {
|
||||||
|
@Test
|
||||||
|
fun testPlus_1_1() {
|
||||||
|
val x = 1.toBigInt()
|
||||||
|
val y = 1.toBigInt()
|
||||||
|
|
||||||
|
val res = x + y
|
||||||
|
val sum = 2.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(sum, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPlusBigNumbers() {
|
||||||
|
val x = 0x7fffffff.toBigInt()
|
||||||
|
val y = 0x7fffffff.toBigInt()
|
||||||
|
val z = 0x7fffffff.toBigInt()
|
||||||
|
|
||||||
|
val res = x + y + z
|
||||||
|
val sum = uintArrayOf(0x7ffffffdU, 0x1U).toBigInt(1)
|
||||||
|
|
||||||
|
assertEquals(sum, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUnaryMinus() {
|
||||||
|
val x = 1234.toBigInt()
|
||||||
|
val y = -1234.toBigInt()
|
||||||
|
assertEquals(-x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinus_2_1() {
|
||||||
|
val x = 2.toBigInt()
|
||||||
|
val y = 1.toBigInt()
|
||||||
|
|
||||||
|
val res = x - y
|
||||||
|
val sum = 1.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(sum, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinus__2_1() {
|
||||||
|
val x = -2.toBigInt()
|
||||||
|
val y = 1.toBigInt()
|
||||||
|
|
||||||
|
val res = x - y
|
||||||
|
val sum = -3.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(sum, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinus___2_1() {
|
||||||
|
val x = -2.toBigInt()
|
||||||
|
val y = 1.toBigInt()
|
||||||
|
|
||||||
|
val res = -x - y
|
||||||
|
val sum = 1.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(sum, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinusBigNumbers() {
|
||||||
|
val x = 12345.toBigInt()
|
||||||
|
val y = 0xffffffffaL.toBigInt()
|
||||||
|
|
||||||
|
val res = x - y
|
||||||
|
val sum = -0xfffffcfc1L.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(sum, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiply_2_3() {
|
||||||
|
val x = 2.toBigInt()
|
||||||
|
val y = 3.toBigInt()
|
||||||
|
|
||||||
|
val res = x * y
|
||||||
|
val prod = 6.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(prod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiply__2_3() {
|
||||||
|
val x = -2.toBigInt()
|
||||||
|
val y = 3.toBigInt()
|
||||||
|
|
||||||
|
val res = x * y
|
||||||
|
val prod = -6.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(prod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiply_0xfff123_0xfff456() {
|
||||||
|
val x = 0xfff123.toBigInt()
|
||||||
|
val y = 0xfff456.toBigInt()
|
||||||
|
|
||||||
|
val res = x * y
|
||||||
|
val prod = 0xffe579ad5dc2L.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(prod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiplyUInt_0xfff123_0xfff456() {
|
||||||
|
val x = 0xfff123.toBigInt()
|
||||||
|
val y = 0xfff456U
|
||||||
|
|
||||||
|
val res = x * y
|
||||||
|
val prod = 0xffe579ad5dc2L.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(prod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiplyInt_0xfff123__0xfff456() {
|
||||||
|
val x = 0xfff123.toBigInt()
|
||||||
|
val y = -0xfff456
|
||||||
|
|
||||||
|
val res = x * y
|
||||||
|
val prod = -0xffe579ad5dc2L.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(prod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiply_0xffffffff_0xffffffff() {
|
||||||
|
val x = 0xffffffffL.toBigInt()
|
||||||
|
val y = 0xffffffffL.toBigInt()
|
||||||
|
|
||||||
|
val res = x * y
|
||||||
|
val prod = 0xfffffffe00000001UL.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(prod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shr_20() {
|
||||||
|
val x = 20.toBigInt()
|
||||||
|
assertEquals(10.toBigInt(), x shr 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shl_20() {
|
||||||
|
val x = 20.toBigInt()
|
||||||
|
assertEquals(40.toBigInt(), x shl 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shl_1_0() {
|
||||||
|
assertEquals(
|
||||||
|
BigInt.ONE,
|
||||||
|
BigInt.ONE shl 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shl_1_32() {
|
||||||
|
assertEquals(
|
||||||
|
0x100000000UL.toBigInt(),
|
||||||
|
BigInt.ONE shl 32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shl_1_33() {
|
||||||
|
assertEquals(
|
||||||
|
0x200000000UL.toBigInt(),
|
||||||
|
BigInt.ONE shl 33
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shr_1_33_33() {
|
||||||
|
assertEquals(
|
||||||
|
BigInt.ONE,
|
||||||
|
(BigInt.ONE shl 33) shr 33
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_shr_1_32() {
|
||||||
|
assertEquals(
|
||||||
|
BigInt.ZERO,
|
||||||
|
BigInt.ONE shr 32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_and_123_456() {
|
||||||
|
val x = 123.toBigInt()
|
||||||
|
val y = 456.toBigInt()
|
||||||
|
assertEquals(72.toBigInt(), x and y)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_or_123_456() {
|
||||||
|
val x = 123.toBigInt()
|
||||||
|
val y = 456.toBigInt()
|
||||||
|
assertEquals(507.toBigInt(), x or y)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_asd() {
|
||||||
|
assertEquals(
|
||||||
|
BigInt.ONE,
|
||||||
|
BigInt.ZERO or ((20.toBigInt() shr 4) and BigInt.ONE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_square_0x11223344U_0xad2ffffdU_0x17eU() {
|
||||||
|
val num =
|
||||||
|
uintArrayOf(0x11223344U, 0xad2ffffdU, 0x17eU).toBigInt(-1)
|
||||||
|
println(num)
|
||||||
|
val res = num * num
|
||||||
|
assertEquals(
|
||||||
|
res,
|
||||||
|
uintArrayOf(0xb0542a10U, 0xbbd85bc8U, 0x2a1fa515U, 0x5069e03bU, 0x23c09U).toBigInt(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDivision_6_3() {
|
||||||
|
val x = 6.toBigInt()
|
||||||
|
val y = 3U
|
||||||
|
|
||||||
|
val res = x / y
|
||||||
|
val div = 2.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(div, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBigDivision_6_3() {
|
||||||
|
val x = 6.toBigInt()
|
||||||
|
val y = 3.toBigInt()
|
||||||
|
|
||||||
|
val res = x / y
|
||||||
|
val div = 2.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(div, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDivision_20__3() {
|
||||||
|
val x = 20.toBigInt()
|
||||||
|
val y = -3
|
||||||
|
|
||||||
|
val res = x / y
|
||||||
|
val div = -6.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(div, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBigDivision_20__3() {
|
||||||
|
val x = 20.toBigInt()
|
||||||
|
val y = -3.toBigInt()
|
||||||
|
|
||||||
|
val res = x / y
|
||||||
|
val div = -6.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(div, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDivision_0xfffffffe00000001_0xffffffff() {
|
||||||
|
val x = 0xfffffffe00000001UL.toBigInt()
|
||||||
|
val y = 0xffffffffU
|
||||||
|
|
||||||
|
val res = x / y
|
||||||
|
val div = 0xffffffffL.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(div, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBigDivision_0xfffffffeabcdef01UL_0xfffffffeabc() {
|
||||||
|
val res = 0xfffffffeabcdef01UL.toBigInt() / 0xfffffffeabc.toBigInt()
|
||||||
|
assertEquals(res, 0x100000.toBigInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBigDivision_0xfffffffe00000001_0xffffffff() {
|
||||||
|
val x = 0xfffffffe00000001UL.toBigInt()
|
||||||
|
val y = 0xffffffffU.toBigInt()
|
||||||
|
|
||||||
|
val res = x / y
|
||||||
|
val div = 0xffffffffL.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(div, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMod_20_3() {
|
||||||
|
val x = 20.toBigInt()
|
||||||
|
val y = 3
|
||||||
|
|
||||||
|
val res = x % y
|
||||||
|
val mod = 2
|
||||||
|
|
||||||
|
assertEquals(mod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBigMod_20_3() {
|
||||||
|
val x = 20.toBigInt()
|
||||||
|
val y = 3.toBigInt()
|
||||||
|
|
||||||
|
val res = x % y
|
||||||
|
val mod = 2.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(mod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMod_0xfffffffe00000001_12345() {
|
||||||
|
val x = 0xfffffffe00000001UL.toBigInt()
|
||||||
|
val y = 12345
|
||||||
|
|
||||||
|
val res = x % y
|
||||||
|
val mod = 1980
|
||||||
|
|
||||||
|
assertEquals(mod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBigMod_0xfffffffe00000001_12345() {
|
||||||
|
val x = 0xfffffffe00000001UL.toBigInt()
|
||||||
|
val y = 12345.toBigInt()
|
||||||
|
|
||||||
|
val res = x % y
|
||||||
|
val mod = 1980.toBigInt()
|
||||||
|
|
||||||
|
assertEquals(mod, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testModPow_3_10_17() {
|
||||||
|
val x = 3.toBigInt()
|
||||||
|
val exp = 10.toBigInt()
|
||||||
|
val mod = 17.toBigInt()
|
||||||
|
|
||||||
|
val res = 8.toBigInt()
|
||||||
|
|
||||||
|
return assertEquals(res, x.modPow(exp, mod))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testModPowBigNumbers() {
|
||||||
|
val x = 0xfffffffeabcdef01UL.toBigInt()
|
||||||
|
val exp = 2.toBigInt()
|
||||||
|
val mod = 0xfffffffeabcUL.toBigInt()
|
||||||
|
|
||||||
|
val res = 0xc2253cde01.toBigInt()
|
||||||
|
|
||||||
|
return assertEquals(res, x.modPow(exp, mod))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testModBigNumbers() {
|
||||||
|
val x = 0xfffffffeabcdef01UL.toBigInt()
|
||||||
|
val mod = 0xfffffffeabcUL.toBigInt()
|
||||||
|
|
||||||
|
val res = 0xdef01.toBigInt()
|
||||||
|
|
||||||
|
return assertEquals(res, x % mod)
|
||||||
|
}
|
||||||
|
}
|
@ -1,543 +0,0 @@
|
|||||||
package scientifik.kmath.operations
|
|
||||||
|
|
||||||
import kotlin.test.Test
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
class KBigIntegerConstructorTest {
|
|
||||||
@Test
|
|
||||||
fun testConstructorZero() {
|
|
||||||
assertEquals(KBigInteger(0), KBigInteger(0, uintArrayOf()))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testConstructor8() {
|
|
||||||
assertEquals(KBigInteger(8), KBigInteger(1, uintArrayOf(8U)))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testConstructor_0xffffffffaL() {
|
|
||||||
val x = KBigInteger(-0xffffffffaL)
|
|
||||||
val y = KBigInteger(-1, uintArrayOf(0xfffffffaU, 0xfU))
|
|
||||||
assertEquals(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
class KBigIntegerCompareTest {
|
|
||||||
@Test
|
|
||||||
fun testCompare1_2() {
|
|
||||||
val x = KBigInteger(1)
|
|
||||||
val y = KBigInteger(2)
|
|
||||||
assertTrue { x < y }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompare0_0() {
|
|
||||||
val x = KBigInteger(0)
|
|
||||||
val y = KBigInteger(0)
|
|
||||||
assertEquals(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompare1__2() {
|
|
||||||
val x = KBigInteger(1)
|
|
||||||
val y = KBigInteger(-2)
|
|
||||||
assertTrue { x > y }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompare_1__2() {
|
|
||||||
val x = KBigInteger(-1)
|
|
||||||
val y = KBigInteger(-2)
|
|
||||||
assertTrue { x > y }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompare_2__1() {
|
|
||||||
val x = KBigInteger(-2)
|
|
||||||
val y = KBigInteger(-1)
|
|
||||||
assertTrue { x < y }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompare12345_12345() {
|
|
||||||
val x = KBigInteger(12345)
|
|
||||||
val y = KBigInteger(12345)
|
|
||||||
assertEquals(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testEqualsWithLong() {
|
|
||||||
val x = KBigInteger(12345)
|
|
||||||
assertTrue { x == KBigInteger(12345L) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testEqualsWithULong() {
|
|
||||||
val x = KBigInteger(12345)
|
|
||||||
assertTrue { x == KBigInteger(12345UL) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompareBigNumbersGreater() {
|
|
||||||
val x = KBigInteger(0xfffffffffL)
|
|
||||||
val y = KBigInteger(0xffffffffaL)
|
|
||||||
assertTrue { x > y }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompareBigNumbersEqual() {
|
|
||||||
val x = KBigInteger(0xffffffffaL)
|
|
||||||
val y = KBigInteger(0xffffffffaL)
|
|
||||||
assertEquals(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompareBigNumbersLess() {
|
|
||||||
val x = KBigInteger(-0xffffffffaL)
|
|
||||||
val y = KBigInteger(0xffffffffaL)
|
|
||||||
assertTrue { x < y }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
class KBigIntegerOperationsTest {
|
|
||||||
@Test
|
|
||||||
fun testPlus_1_1() {
|
|
||||||
val x = KBigInteger(1)
|
|
||||||
val y = KBigInteger(1)
|
|
||||||
|
|
||||||
val res = x + y
|
|
||||||
val sum = KBigInteger(2)
|
|
||||||
|
|
||||||
assertEquals(sum, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testPlusBigNumbers() {
|
|
||||||
val x = KBigInteger(0x7fffffff)
|
|
||||||
val y = KBigInteger(0x7fffffff)
|
|
||||||
val z = KBigInteger(0x7fffffff)
|
|
||||||
|
|
||||||
val res = x + y + z
|
|
||||||
val sum = KBigInteger(1, uintArrayOf(0x7ffffffdU, 0x1U))
|
|
||||||
|
|
||||||
assertEquals(sum, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testUnaryMinus() {
|
|
||||||
val x = KBigInteger(1234)
|
|
||||||
val y = KBigInteger(-1234)
|
|
||||||
assertEquals(-x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMinus_2_1() {
|
|
||||||
val x = KBigInteger(2)
|
|
||||||
val y = KBigInteger(1)
|
|
||||||
|
|
||||||
val res = x - y
|
|
||||||
val sum = KBigInteger(1)
|
|
||||||
|
|
||||||
assertEquals(sum, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMinus__2_1() {
|
|
||||||
val x = KBigInteger(-2)
|
|
||||||
val y = KBigInteger(1)
|
|
||||||
|
|
||||||
val res = x - y
|
|
||||||
val sum = KBigInteger(-3)
|
|
||||||
|
|
||||||
assertEquals(sum, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMinus___2_1() {
|
|
||||||
val x = KBigInteger(-2)
|
|
||||||
val y = KBigInteger(1)
|
|
||||||
|
|
||||||
val res = -x - y
|
|
||||||
val sum = KBigInteger(1)
|
|
||||||
|
|
||||||
assertEquals(sum, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMinusBigNumbers() {
|
|
||||||
val x = KBigInteger(12345)
|
|
||||||
val y = KBigInteger(0xffffffffaL)
|
|
||||||
|
|
||||||
val res = x - y
|
|
||||||
val sum = KBigInteger(-0xfffffcfc1L)
|
|
||||||
|
|
||||||
assertEquals(sum, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMultiply_2_3() {
|
|
||||||
val x = KBigInteger(2)
|
|
||||||
val y = KBigInteger(3)
|
|
||||||
|
|
||||||
val res = x * y
|
|
||||||
val prod = KBigInteger(6)
|
|
||||||
|
|
||||||
assertEquals(prod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMultiply__2_3() {
|
|
||||||
val x = KBigInteger(-2)
|
|
||||||
val y = KBigInteger(3)
|
|
||||||
|
|
||||||
val res = x * y
|
|
||||||
val prod = KBigInteger(-6)
|
|
||||||
|
|
||||||
assertEquals(prod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMultiply_0xfff123_0xfff456() {
|
|
||||||
val x = KBigInteger(0xfff123)
|
|
||||||
val y = KBigInteger(0xfff456)
|
|
||||||
|
|
||||||
val res = x * y
|
|
||||||
val prod = KBigInteger(0xffe579ad5dc2L)
|
|
||||||
|
|
||||||
assertEquals(prod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMultiplyUInt_0xfff123_0xfff456() {
|
|
||||||
val x = KBigInteger(0xfff123)
|
|
||||||
val y = 0xfff456U
|
|
||||||
|
|
||||||
val res = x * y
|
|
||||||
val prod = KBigInteger(0xffe579ad5dc2L)
|
|
||||||
|
|
||||||
assertEquals(prod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMultiplyInt_0xfff123__0xfff456() {
|
|
||||||
val x = KBigInteger(0xfff123)
|
|
||||||
val y = -0xfff456
|
|
||||||
|
|
||||||
val res = x * y
|
|
||||||
val prod = KBigInteger(-0xffe579ad5dc2L)
|
|
||||||
|
|
||||||
assertEquals(prod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMultiply_0xffffffff_0xffffffff() {
|
|
||||||
val x = KBigInteger(0xffffffffL)
|
|
||||||
val y = KBigInteger(0xffffffffL)
|
|
||||||
|
|
||||||
val res = x * y
|
|
||||||
val prod = KBigInteger(0xfffffffe00000001UL)
|
|
||||||
|
|
||||||
assertEquals(prod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shr_20() {
|
|
||||||
val x = KBigInteger(20)
|
|
||||||
assertEquals(KBigInteger(10), x shr 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shl_20() {
|
|
||||||
val x = KBigInteger(20)
|
|
||||||
assertEquals(KBigInteger(40), x shl 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shl_1_0() {
|
|
||||||
assertEquals(KBigInteger.ONE, KBigInteger.ONE shl 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shl_1_32() {
|
|
||||||
assertEquals(KBigInteger(0x100000000UL), KBigInteger.ONE shl 32)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shl_1_33() {
|
|
||||||
assertEquals(KBigInteger(0x200000000UL), KBigInteger.ONE shl 33)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shr_1_33_33() {
|
|
||||||
assertEquals(KBigInteger.ONE, (KBigInteger.ONE shl 33) shr 33)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_shr_1_32() {
|
|
||||||
assertEquals(KBigInteger.ZERO, KBigInteger.ONE shr 32)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_and_123_456() {
|
|
||||||
val x = KBigInteger(123)
|
|
||||||
val y = KBigInteger(456)
|
|
||||||
assertEquals(KBigInteger(72), x and y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_or_123_456() {
|
|
||||||
val x = KBigInteger(123)
|
|
||||||
val y = KBigInteger(456)
|
|
||||||
assertEquals(KBigInteger(507), x or y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_asd() {
|
|
||||||
assertEquals(KBigInteger.ONE, KBigInteger.ZERO or ((KBigInteger(20) shr 4) and KBigInteger.ONE))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_square_0x11223344U_0xad2ffffdU_0x17eU() {
|
|
||||||
val num = KBigInteger(-1, uintArrayOf(0x11223344U, 0xad2ffffdU, 0x17eU ))
|
|
||||||
println(num)
|
|
||||||
val res = num * num
|
|
||||||
assertEquals(res, KBigInteger(1, uintArrayOf(0xb0542a10U, 0xbbd85bc8U, 0x2a1fa515U, 0x5069e03bU, 0x23c09U)))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testDivision_6_3() {
|
|
||||||
val x = KBigInteger(6)
|
|
||||||
val y = 3U
|
|
||||||
|
|
||||||
val res = x / y
|
|
||||||
val div = KBigInteger(2)
|
|
||||||
|
|
||||||
assertEquals(div, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBigDivision_6_3() {
|
|
||||||
val x = KBigInteger(6)
|
|
||||||
val y = KBigInteger(3)
|
|
||||||
|
|
||||||
val res = x / y
|
|
||||||
val div = KBigInteger(2)
|
|
||||||
|
|
||||||
assertEquals(div, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testDivision_20__3() {
|
|
||||||
val x = KBigInteger(20)
|
|
||||||
val y = -3
|
|
||||||
|
|
||||||
val res = x / y
|
|
||||||
val div = KBigInteger(-6)
|
|
||||||
|
|
||||||
assertEquals(div, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBigDivision_20__3() {
|
|
||||||
val x = KBigInteger(20)
|
|
||||||
val y = KBigInteger(-3)
|
|
||||||
|
|
||||||
val res = x / y
|
|
||||||
val div = KBigInteger(-6)
|
|
||||||
|
|
||||||
assertEquals(div, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testDivision_0xfffffffe00000001_0xffffffff() {
|
|
||||||
val x = KBigInteger(0xfffffffe00000001UL)
|
|
||||||
val y = 0xffffffffU
|
|
||||||
|
|
||||||
val res = x / y
|
|
||||||
val div = KBigInteger(0xffffffffL)
|
|
||||||
|
|
||||||
assertEquals(div, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBigDivision_0xfffffffeabcdef01UL_0xfffffffeabc() {
|
|
||||||
val res = KBigInteger(0xfffffffeabcdef01UL) / KBigInteger(0xfffffffeabc)
|
|
||||||
assertEquals(res, KBigInteger(0x100000))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBigDivision_0xfffffffe00000001_0xffffffff() {
|
|
||||||
val x = KBigInteger(0xfffffffe00000001UL)
|
|
||||||
val y = KBigInteger(0xffffffffU)
|
|
||||||
|
|
||||||
val res = x / y
|
|
||||||
val div = KBigInteger(0xffffffffL)
|
|
||||||
|
|
||||||
assertEquals(div, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMod_20_3() {
|
|
||||||
val x = KBigInteger(20)
|
|
||||||
val y = 3
|
|
||||||
|
|
||||||
val res = x % y
|
|
||||||
val mod = 2
|
|
||||||
|
|
||||||
assertEquals(mod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBigMod_20_3() {
|
|
||||||
val x = KBigInteger(20)
|
|
||||||
val y = KBigInteger(3)
|
|
||||||
|
|
||||||
val res = x % y
|
|
||||||
val mod = KBigInteger(2)
|
|
||||||
|
|
||||||
assertEquals(mod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMod_0xfffffffe00000001_12345() {
|
|
||||||
val x = KBigInteger(0xfffffffe00000001UL)
|
|
||||||
val y = 12345
|
|
||||||
|
|
||||||
val res = x % y
|
|
||||||
val mod = 1980
|
|
||||||
|
|
||||||
assertEquals(mod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBigMod_0xfffffffe00000001_12345() {
|
|
||||||
val x = KBigInteger(0xfffffffe00000001UL)
|
|
||||||
val y = KBigInteger(12345)
|
|
||||||
|
|
||||||
val res = x % y
|
|
||||||
val mod = KBigInteger(1980)
|
|
||||||
|
|
||||||
assertEquals(mod, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testModPow_3_10_17() {
|
|
||||||
val x = KBigInteger(3)
|
|
||||||
val exp = KBigInteger(10)
|
|
||||||
val mod = KBigInteger(17)
|
|
||||||
|
|
||||||
val res = KBigInteger(8)
|
|
||||||
|
|
||||||
return assertEquals(res, x.modPow(exp, mod))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testModPowBigNumbers() {
|
|
||||||
val x = KBigInteger(0xfffffffeabcdef01UL)
|
|
||||||
val exp = KBigInteger(2)
|
|
||||||
val mod = KBigInteger(0xfffffffeabcUL)
|
|
||||||
|
|
||||||
val res = KBigInteger(0xc2253cde01)
|
|
||||||
|
|
||||||
return assertEquals(res, x.modPow(exp, mod))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testModBigNumbers() {
|
|
||||||
val x = KBigInteger(0xfffffffeabcdef01UL)
|
|
||||||
val mod = KBigInteger(0xfffffffeabcUL)
|
|
||||||
|
|
||||||
val res = KBigInteger(0xdef01)
|
|
||||||
|
|
||||||
return assertEquals(res, x % mod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.ExperimentalUnsignedTypes
|
|
||||||
class KBigIntegerConversionsTest {
|
|
||||||
@Test
|
|
||||||
fun testToString0x10() {
|
|
||||||
val x = KBigInteger(0x10)
|
|
||||||
assertEquals("0x10", x.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testToString0x17ffffffd() {
|
|
||||||
val x = KBigInteger(0x17ffffffdL)
|
|
||||||
assertEquals("0x17ffffffd", x.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testToString_0x17ead2ffffd() {
|
|
||||||
val x = KBigInteger(-0x17ead2ffffdL)
|
|
||||||
assertEquals("-0x17ead2ffffd", x.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testToString_0x17ead2ffffd11223344() {
|
|
||||||
val x = KBigInteger(-1, uintArrayOf(0x11223344U, 0xad2ffffdU, 0x17eU ))
|
|
||||||
assertEquals("-0x17ead2ffffd11223344", x.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testFromString_0x17ead2ffffd11223344() {
|
|
||||||
val x = "0x17ead2ffffd11223344".toKBigInteger()
|
|
||||||
assertEquals( "0x17ead2ffffd11223344", x.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testFromString_7059135710711894913860() {
|
|
||||||
val x = "-7059135710711894913860".toKBigInteger()
|
|
||||||
assertEquals("-0x17ead2ffffd11223344", x.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KBigIntegerRingTest {
|
|
||||||
@Test
|
|
||||||
fun testKBigIntegerRingSum() {
|
|
||||||
val res = KBigIntegerRing {
|
|
||||||
KBigInteger(1_000L) * KBigInteger(1_000L)
|
|
||||||
}
|
|
||||||
assertEquals(res, KBigInteger(1_000_000) )
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testKBigIntegerRingSum_100_000_000__100_000_000() {
|
|
||||||
KBigIntegerRing {
|
|
||||||
val sum = +"100_000_000" + +"100_000_000"
|
|
||||||
assertEquals(sum, "200_000_000".toKBigInteger())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_mul_3__4() {
|
|
||||||
KBigIntegerRing {
|
|
||||||
val prod = +"0x3000_0000_0000" * +"0x4000_0000_0000_0000_0000"
|
|
||||||
assertEquals(prod, "0xc00_0000_0000_0000_0000_0000_0000_0000".toKBigInteger())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_div_big_1() {
|
|
||||||
KBigIntegerRing {
|
|
||||||
val res = +"1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000" /
|
|
||||||
+"555_000_444_000_333_000_222_000_111_000_999_001"
|
|
||||||
assertEquals(res, +"1801800360360432432518919022699")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun test_rem_big_1() {
|
|
||||||
KBigIntegerRing {
|
|
||||||
val res = +"1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000" %
|
|
||||||
+"555_000_444_000_333_000_222_000_111_000_999_001"
|
|
||||||
assertEquals(res, +"324121220440768000291647788404676301")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user