commonMain.com.ionspin.kotlin.bignum.integer.BigInteger.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bignum-jvm Show documentation
Show all versions of bignum-jvm Show documentation
Kotlin Multiplatform BigNum library
/*
* Copyright 2019 Ugljesa Jovanovic
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.ionspin.kotlin.bignum.integer
import com.ionspin.kotlin.bignum.BigNumber
import com.ionspin.kotlin.bignum.BitwiseCapable
import com.ionspin.kotlin.bignum.ByteArrayDeserializable
import com.ionspin.kotlin.bignum.ByteArraySerializable
import com.ionspin.kotlin.bignum.CommonBigNumberOperations
import com.ionspin.kotlin.bignum.NarrowingOperations
import com.ionspin.kotlin.bignum.decimal.BigDecimal
import com.ionspin.kotlin.bignum.integer.base63.array.BigInteger63Arithmetic
import com.ionspin.kotlin.bignum.modular.ModularBigInteger
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.log10
/**
* Arbitrary precision integer arithmetic.
*
* Based on unsigned arrays, currently limited to [Int.MAX_VALUE] words.
*/
class BigInteger internal constructor(wordArray: WordArray, requestedSign: Sign) : BigNumber,
CommonBigNumberOperations,
NarrowingOperations,
BitwiseCapable, Comparable,
ByteArraySerializable {
constructor(long: Long) : this(arithmetic.fromLong(long), determinSignFromNumber(long))
constructor(int: Int) : this(arithmetic.fromInt(int), determinSignFromNumber(int))
constructor(short: Short) : this(arithmetic.fromShort(short), determinSignFromNumber(short))
constructor(byte: Byte) : this(arithmetic.fromByte(byte), determinSignFromNumber(byte))
init {
if (requestedSign == Sign.ZERO) {
require(isResultZero(wordArray)) {
"sign should be Sign.ZERO iff magnitude has a value of 0"
}
}
}
override fun getCreator(): BigNumber.Creator {
return BigInteger
}
override fun getInstance(): BigInteger {
return this
}
companion object : BigNumber.Creator, BigNumber.Util, ByteArrayDeserializable {
private val arithmetic: BigIntegerArithmetic = chosenArithmetic
override val ZERO = BigInteger(arithmetic.ZERO, Sign.ZERO)
override val ONE = BigInteger(arithmetic.ONE, Sign.POSITIVE)
override val TWO = BigInteger(arithmetic.TWO, Sign.POSITIVE)
override val TEN = BigInteger(arithmetic.TEN, Sign.POSITIVE)
val LOG_10_OF_2 = log10(2.0)
override fun parseString(string: String, base: Int): BigInteger {
val decimal = string.contains('.')
if (decimal) {
val bigDecimal = BigDecimal.parseString(string)
val isActuallyDecimal = (bigDecimal - bigDecimal.floor()) > 0
if (isActuallyDecimal) {
throw NumberFormatException("Supplied string is decimal, which cannot be converted to BigInteger without precision loss.")
}
return bigDecimal.toBigInteger()
}
val signed = (string[0] == '-' || string[0] == '+')
return if (signed) {
if (string.length == 1) {
throw NumberFormatException("Invalid big integer: $string")
}
val isNegative = if (string[0] == '-') {
Sign.NEGATIVE
} else {
Sign.POSITIVE
}
if (string.length == 2 && string[1] == '0') {
return ZERO
}
BigInteger(
arithmetic.parseForBase(string.substring(startIndex = 1, endIndex = string.length), base),
isNegative
)
} else {
if (string.length == 1 && string[0] == '0') {
return ZERO
}
BigInteger(arithmetic.parseForBase(string, base), Sign.POSITIVE)
}
}
internal fun fromWordArray(wordArray: WordArray, sign: Sign): BigInteger {
return BigInteger(wordArray, sign)
}
private inline fun determinSignFromNumber(number: Comparable): Sign {
return when (T::class) {
Long::class -> {
number as Long
when {
number < 0 -> Sign.NEGATIVE
number > 0 -> Sign.POSITIVE
else -> Sign.ZERO
}
}
Int::class -> {
number as Int
when {
number < 0 -> Sign.NEGATIVE
number > 0 -> Sign.POSITIVE
else -> Sign.ZERO
}
}
Short::class -> {
number as Short
when {
number < 0 -> Sign.NEGATIVE
number > 0 -> Sign.POSITIVE
else -> Sign.ZERO
}
}
Byte::class -> {
number as Byte
when {
number < 0 -> Sign.NEGATIVE
number > 0 -> Sign.POSITIVE
else -> Sign.ZERO
}
}
else -> throw RuntimeException("Unsupported type ${T::class}")
}
}
// BigIntegers are immutable so this is pointless, but the rest of creator implementations use this.
override fun fromBigInteger(bigInteger: BigInteger): BigInteger {
return bigInteger
}
override fun fromULong(uLong: ULong) = BigInteger(arithmetic.fromULong(uLong), Sign.POSITIVE)
override fun fromUInt(uInt: UInt) = BigInteger(arithmetic.fromUInt(uInt), Sign.POSITIVE)
override fun fromUShort(uShort: UShort) = BigInteger(arithmetic.fromUShort(uShort), Sign.POSITIVE)
override fun fromUByte(uByte: UByte) = BigInteger(arithmetic.fromUByte(uByte), Sign.POSITIVE)
override fun fromLong(long: Long) = BigInteger(long)
override fun fromInt(int: Int) = BigInteger(int)
override fun fromShort(short: Short) = BigInteger(short)
override fun fromByte(byte: Byte) = BigInteger(byte)
override fun tryFromFloat(float: Float, exactRequired: Boolean): BigInteger {
val floatDecimalPart = float - floor(float)
val bigDecimal = BigDecimal.fromFloat(floor(float), null)
if (exactRequired) {
if (floatDecimalPart > 0) {
throw ArithmeticException("Cant create BigInteger without precision loss, and exact value was required")
}
}
return bigDecimal.toBigInteger()
}
override fun tryFromDouble(double: Double, exactRequired: Boolean): BigInteger {
val doubleDecimalPart = double - floor(double)
val bigDecimal = BigDecimal.fromDouble(floor(double), null)
if (exactRequired) {
if (doubleDecimalPart > 0) {
throw ArithmeticException("Cant create BigInteger without precision loss, and exact value was required")
}
}
return bigDecimal.toBigInteger()
}
override fun max(first: BigInteger, second: BigInteger): BigInteger {
return if (first > second) {
first
} else {
second
}
}
override fun min(first: BigInteger, second: BigInteger): BigInteger {
return if (first < second) {
first
} else {
second
}
}
override fun fromUByteArray(
source: UByteArray,
sign: Sign
): BigInteger {
val result = arithmetic.fromUByteArray(source)
return BigInteger(result, sign)
}
override fun fromByteArray(
source: ByteArray,
sign: Sign
): BigInteger {
val result = arithmetic.fromByteArray(source)
return BigInteger(result, sign)
}
}
internal val magnitude: WordArray = BigInteger63Arithmetic.removeLeadingZeros(wordArray)
internal val sign: Sign = if (isResultZero(magnitude)) {
Sign.ZERO
} else {
requestedSign
}
private fun isResultZero(resultMagnitude: WordArray): Boolean {
return arithmetic.compare(resultMagnitude, arithmetic.ZERO) == 0
}
val numberOfWords = magnitude.size
var stringRepresentation: String? = null
override fun add(other: BigInteger): BigInteger {
val comparison = arithmetic.compare(this.magnitude, other.magnitude)
return if (other.sign == this.sign) {
return BigInteger(arithmetic.add(this.magnitude, other.magnitude), sign)
} else {
when {
comparison > 0 -> {
BigInteger(arithmetic.subtract(this.magnitude, other.magnitude), sign)
}
comparison < 0 -> {
BigInteger(arithmetic.subtract(other.magnitude, this.magnitude), other.sign)
}
else -> {
ZERO
}
}
}
}
override fun subtract(other: BigInteger): BigInteger {
val comparison = arithmetic.compare(this.magnitude, other.magnitude)
if (this == ZERO) {
return other.negate()
}
if (other == ZERO) {
return this
}
return if (other.sign == this.sign) {
when {
comparison > 0 -> {
BigInteger(arithmetic.subtract(this.magnitude, other.magnitude), sign)
}
comparison < 0 -> {
BigInteger(arithmetic.subtract(other.magnitude, this.magnitude), !sign)
}
else -> {
ZERO
}
}
} else {
return BigInteger(arithmetic.add(this.magnitude, other.magnitude), sign)
}
}
override fun multiply(other: BigInteger): BigInteger {
if (this.isZero() || other.isZero()) {
return ZERO
}
if (other == ONE) {
return this
}
val sign = if (this.sign != other.sign) {
Sign.NEGATIVE
} else {
Sign.POSITIVE
}
return if (sign == Sign.POSITIVE) {
BigInteger(arithmetic.multiply(this.magnitude, other.magnitude), sign)
} else {
BigInteger(arithmetic.multiply(this.magnitude, other.magnitude), sign)
}
}
override fun divide(other: BigInteger): BigInteger {
if (other.isZero()) {
throw ArithmeticException("Division by zero! $this / $other")
}
val result = arithmetic.divide(this.magnitude, other.magnitude).first
return if (result == arithmetic.ZERO) {
ZERO
} else {
val sign = if (this.sign != other.sign) {
Sign.NEGATIVE
} else {
Sign.POSITIVE
}
BigInteger(result, sign)
}
}
/**
* Returns the remainder of division operation. Uses truncating division, which means
* that the sign of remainder will be same as sign of dividend
*/
override fun remainder(other: BigInteger): BigInteger {
if (other.isZero()) {
throw ArithmeticException("Division by zero! $this / $other")
}
var sign = if (this.sign != other.sign) {
Sign.NEGATIVE
} else {
Sign.POSITIVE
}
val result = arithmetic.divide(this.magnitude, other.magnitude).second
if (result == arithmetic.ZERO) {
sign = Sign.ZERO
}
return BigInteger(result, sign)
}
override fun divideAndRemainder(other: BigInteger): Pair {
if (other.isZero()) {
throw ArithmeticException("Division by zero! $this / $other")
}
val sign = if (this.sign != other.sign) {
Sign.NEGATIVE
} else {
Sign.POSITIVE
}
val result = arithmetic.divide(this.magnitude, other.magnitude)
val quotient = if (result.first == arithmetic.ZERO) {
ZERO
} else {
BigInteger(result.first, sign)
}
val remainder = if (result.second == arithmetic.ZERO) {
ZERO
} else {
BigInteger(result.second, this.sign)
}
return Pair(
quotient,
remainder
)
}
/**
* D1Balanced reciprocal
*/
private fun d1reciprocalRecursive(): BigInteger {
return BigInteger(arithmetic.reciprocal(this.magnitude).first, sign)
}
fun sqrt(): BigInteger {
return BigInteger(arithmetic.sqrt(magnitude).first, this.sign)
}
fun sqrtAndRemainder(): SqareRootAndRemainder {
return SqareRootAndRemainder(
BigInteger(arithmetic.sqrt(magnitude).first, this.sign),
BigInteger(arithmetic.sqrt(magnitude).second, this.sign)
)
}
fun gcd(other: BigInteger): BigInteger {
return BigInteger(arithmetic.gcd(this.magnitude, other.magnitude), Sign.POSITIVE)
}
private fun naiveGcd(other: BigInteger): BigInteger {
var u = this
var v = other
while (v != ZERO) {
val tmpU = u
u = v
v = tmpU % v
}
return u
}
fun modInverse(modulo: BigInteger): BigInteger {
if (gcd(modulo) != ONE) {
throw ArithmeticException("BigInteger is not invertible. This and modulus are not relatively prime (coprime)")
}
var u = ONE
var w = ZERO
var b = this
var c = modulo
while (c != ZERO) {
val (q, r) = b divrem c
b = c
c = r
val tmpU = u
u = w
w = tmpU - q * w
}
return u
}
/**
* Returns an always positive remainder of division operation
*/
infix fun mod(modulo: BigInteger): BigInteger {
val result = this % modulo
return if (result < 0) {
result + modulo
} else {
result
}
}
fun compare(other: BigInteger): Int {
if (isZero() && other.isZero()) return 0
if (other.isZero() && this.sign == Sign.POSITIVE) return 1
if (other.isZero() && this.sign == Sign.NEGATIVE) return -1
if (this.isZero() && other.sign == Sign.POSITIVE) return -1
if (this.isZero() && other.sign == Sign.NEGATIVE) return 1
if (sign != other.sign) return if (sign == Sign.POSITIVE) 1 else -1
val result = arithmetic.compare(this.magnitude, other.magnitude)
return if (this.sign == Sign.NEGATIVE && other.sign == Sign.NEGATIVE) {
result * -1
} else {
result
}
}
override fun isZero(): Boolean {
return this.sign == Sign.ZERO ||
chosenArithmetic.compare(this.magnitude, chosenArithmetic.ZERO) == 0
}
override fun negate(): BigInteger {
return BigInteger(wordArray = this.magnitude, requestedSign = sign.not())
}
override fun abs(): BigInteger {
return BigInteger(wordArray = this.magnitude, requestedSign = Sign.POSITIVE)
}
fun pow(exponent: BigInteger): BigInteger {
if (exponent <= Long.MAX_VALUE) {
return pow(exponent.magnitude[0].toLong())
}
// TODO this is not efficient
var counter = exponent
var result = ONE
while (counter > 0) {
counter--
result *= this
}
return result
}
override fun pow(exponent: Long): BigInteger {
if (exponent < 0) {
throw ArithmeticException("Negative exponent not supported with BigInteger")
}
return when (this) {
ZERO -> ZERO
ONE -> ONE
else -> {
val sign = if (sign == Sign.NEGATIVE) {
if (exponent % 2 == 0L) {
Sign.POSITIVE
} else {
Sign.NEGATIVE
}
} else {
Sign.POSITIVE
}
BigInteger(arithmetic.pow(magnitude, exponent), sign)
}
}
}
override fun pow(exponent: Int): BigInteger {
return pow(exponent.toLong())
}
override fun signum(): Int = when (sign) {
Sign.POSITIVE -> 1
Sign.NEGATIVE -> -1
Sign.ZERO -> 0
}
override fun bitAt(position: Long): Boolean {
return arithmetic.bitAt(magnitude, position)
}
override fun setBitAt(position: Long, bit: Boolean): BigInteger {
return BigInteger(arithmetic.setBitAt(magnitude, position, bit), sign)
}
override fun numberOfDecimalDigits(): Long {
val bitLenght = arithmetic.bitLength(magnitude)
val minDigit = ceil((bitLenght - 1) * LOG_10_OF_2)
// val maxDigit = floor(bitLenght * LOG_10_OF_2) + 1
// val correct = this / 10.toBigInteger().pow(maxDigit.toInt())
// return when {
// correct == ZERO -> maxDigit.toInt() - 1
// correct > 0 && correct < 10 -> maxDigit.toInt()
// else -> -1
// }
var tmp = this / 10.toBigInteger().pow(minDigit.toInt())
var counter = 0L
while (tmp.compareTo(0) != 0) {
tmp /= 10
counter++
}
return counter + minDigit.toInt()
}
override infix fun shl(places: Int): BigInteger {
return BigInteger(arithmetic.shiftLeft(this.magnitude, places), sign)
}
override infix fun shr(places: Int): BigInteger {
val result = BigInteger(arithmetic.shiftRight(this.magnitude, places), sign)
if (result.magnitude == arithmetic.ZERO) {
return ZERO
}
return result
}
override operator fun unaryMinus(): BigInteger = negate()
override fun secureOverwrite() {
for (i in 0 until magnitude.size) {
magnitude[i] = 0U
}
}
operator fun dec(): BigInteger {
return this - ONE
}
operator fun inc(): BigInteger {
return this + ONE
}
infix fun divrem(other: BigInteger): QuotientAndRemainder {
val result = divideAndRemainder(other)
return QuotientAndRemainder(result.first, result.second)
}
override infix fun and(other: BigInteger): BigInteger {
return BigInteger(arithmetic.and(this.magnitude, other.magnitude), sign)
}
override infix fun or(other: BigInteger): BigInteger {
return BigInteger(arithmetic.or(this.magnitude, other.magnitude), sign)
}
override infix fun xor(other: BigInteger): BigInteger {
val resultMagnitude = arithmetic.xor(this.magnitude, other.magnitude)
val resultSign = when {
this.isNegative xor other.isNegative -> Sign.NEGATIVE
isResultZero(resultMagnitude) -> Sign.ZERO
else -> Sign.POSITIVE
}
return BigInteger(resultMagnitude, resultSign)
}
/**
* Inverts only up to chosen [arithmetic] [BigIntegerArithmetic.bitLength] bits.
* This is different from Java biginteger which returns inverse in two's complement.
*
* I.e.: If the number was "1100" binary, not returns "0011" => "11" => 4 decimal
*/
override fun not(): BigInteger {
return BigInteger(arithmetic.not(this.magnitude), sign)
}
override fun compareTo(other: Any): Int {
if (other is Number) {
if (ComparisonWorkaround.isSpecialHandlingForFloatNeeded(other)) {
return javascriptNumberComparison(other)
}
}
return when (other) {
is BigInteger -> compare(other)
is Long -> compare(fromLong(other))
is Int -> compare(fromInt(other))
is Short -> compare(fromShort(other))
is Byte -> compare(fromByte(other))
is ULong -> compare(fromULong(other))
is UInt -> compare(fromUInt(other))
is UShort -> compare(fromUShort(other))
is UByte -> compare(fromUByte(other))
is Float -> compareFloatAndBigInt(other) { compare(it) }
is Double -> compareDoubleAndBigInt(other) { compare(it) }
else -> throw RuntimeException("Invalid comparison type for BigInteger: ${other::class}")
}
}
/**
* Javascrpt doesn't have different types for float, integer, long, it's all just "number", so we need
* to check if it's a decimal or integer number before comparing.
*/
private fun javascriptNumberComparison(number: Number): Int {
val float = number.toFloat()
return when {
float % 1 == 0f -> compare(fromLong(number.toLong()))
else -> compareFloatAndBigInt(number.toFloat()) { compare(it) }
}
}
fun compareFloatAndBigInt(float: Float, comparisonBlock: (BigInteger) -> Int): Int {
val withoutDecimalPart = floor(float)
val hasDecimalPart = (float % 1 != 0f)
return if (hasDecimalPart) {
val comparisonResult = comparisonBlock.invoke(tryFromFloat(withoutDecimalPart + 1))
if (comparisonResult == 0) {
// They were equal with float incremented by one (because of decimal part) so the BigInt was larger
1
} else {
comparisonResult
}
} else {
comparisonBlock.invoke(tryFromFloat(withoutDecimalPart))
}
}
fun compareDoubleAndBigInt(double: Double, comparisonBlock: (BigInteger) -> Int): Int {
val withoutDecimalPart = floor(double)
val hasDecimalPart = (double % 1 != 0.0)
return if (hasDecimalPart) {
val comparisonResult = comparisonBlock.invoke(tryFromDouble(withoutDecimalPart + 1))
if (comparisonResult == 0) {
// They were equal with double incremented by one (because of decimal part) so the BigInt was larger
1
} else {
comparisonResult
}
} else {
comparisonBlock.invoke(tryFromDouble(withoutDecimalPart))
}
}
override fun equals(other: Any?): Boolean {
val comparison = when (other) {
is BigInteger -> compare(other)
is Long -> compare(fromLong(other))
is Int -> compare(fromInt(other))
is Short -> compare(fromShort(other))
is Byte -> compare(fromByte(other))
is ULong -> compare(fromULong(other))
is UInt -> compare(fromUInt(other))
is UShort -> compare(fromUShort(other))
is UByte -> compare(fromUByte(other))
else -> -1
}
return comparison == 0
}
override fun hashCode(): Int {
return magnitude.hashCode() + sign.hashCode()
}
override fun toString(): String {
// TODO think about limiting the size of string, and offering a stream of characters instead of huge strings
// if (stringRepresentation == null) {
// stringRepresentation = toString(10)
// }
// return stringRepresentation!!
// Linux build complains about mutating a frozen object, let's try without this representation caching
return toString(10)
}
override fun toString(base: Int): String {
val sign = if (sign == Sign.NEGATIVE) {
"-"
} else {
""
}
return sign + toStringWithoutSign(base)
}
internal fun toStringWithoutSign(base: Int): String {
return arithmetic.toString(this.magnitude, base)
}
data class QuotientAndRemainder(val quotient: BigInteger, val remainder: BigInteger)
data class SqareRootAndRemainder(val squareRoot: BigInteger, val remainder: BigInteger)
// TODO eh
operator fun times(char: Char): String {
if (this < 0) {
throw RuntimeException("Char cannot be multiplied with negative number")
}
var counter = this
val stringBuilder = StringBuilder()
while (counter > 0) {
stringBuilder.append(char)
counter--
}
return stringBuilder.toString()
}
fun toModularBigInteger(modulo: BigInteger): ModularBigInteger {
val creator = ModularBigInteger.creatorForModulo(modulo)
return creator.fromBigInteger(this)
}
override fun intValue(exactRequired: Boolean): Int {
if (exactRequired && (this > Int.MAX_VALUE || this < Int.MIN_VALUE)) {
throw ArithmeticException("Cannot convert to int and provide exact value")
}
return magnitude[0].toInt() * signum()
}
override fun longValue(exactRequired: Boolean): Long {
if (exactRequired && (this > Long.MAX_VALUE || this < Long.MIN_VALUE)) {
throw ArithmeticException("Cannot convert to long and provide exact value")
}
return if (magnitude.size > 1) {
val firstBit = magnitude[1] shl 63
(magnitude[0].toLong() or firstBit.toLong()) * signum()
} else {
return magnitude[0].toLong()
}
}
override fun byteValue(exactRequired: Boolean): Byte {
if (exactRequired && (this > Byte.MAX_VALUE || this < Byte.MIN_VALUE)) {
throw ArithmeticException("Cannot convert to byte and provide exact value")
}
return (magnitude[0].toByte() * signum()).toByte()
}
override fun shortValue(exactRequired: Boolean): Short {
if (exactRequired && (this > Short.MAX_VALUE || this < Short.MIN_VALUE)) {
throw ArithmeticException("Cannot convert to short and provide exact value")
}
return (magnitude[0].toShort() * signum()).toShort()
}
override fun uintValue(exactRequired: Boolean): UInt {
if (exactRequired && (this > UInt.MAX_VALUE || isNegative)) {
throw ArithmeticException("Cannot convert to unsigned int and provide exact value")
}
return magnitude[0].toUInt()
}
override fun ulongValue(exactRequired: Boolean): ULong {
if (exactRequired && (this > ULong.MAX_VALUE || isNegative)) {
throw ArithmeticException("Cannot convert to unsigned long and provide exact value")
}
return if (magnitude.size > 1) {
val firstBit = magnitude[1] shl 63
magnitude[0] or firstBit
} else {
return magnitude[0]
}
}
override fun ubyteValue(exactRequired: Boolean): UByte {
if (exactRequired && (this > UByte.MAX_VALUE.toUInt() || isNegative)) {
throw ArithmeticException("Cannot convert to unsigned byte and provide exact value")
}
return magnitude[0].toUByte()
}
override fun ushortValue(exactRequired: Boolean): UShort {
if (exactRequired && this > UShort.MAX_VALUE.toUInt() || isNegative) {
throw ArithmeticException("Cannot convert to unsigned short and provide exact value")
}
return magnitude[0].toUShort()
}
override fun floatValue(exactRequired: Boolean): Float {
if (exactRequired && this.abs() > Float.MAX_VALUE) {
throw ArithmeticException("Cannot convert to float and provide exact value")
}
return this.toString().toFloat()
}
override fun doubleValue(exactRequired: Boolean): Double {
if (exactRequired && this.abs() > Double.MAX_VALUE) {
throw ArithmeticException("Cannot convert to float and provide exact value")
}
return this.toString().toDouble()
}
override fun toUByteArray(): UByteArray {
return arithmetic.toUByteArray(magnitude)
}
override fun toByteArray(): ByteArray {
return arithmetic.toByteArray(magnitude)
}
operator fun rangeTo(other: BigInteger) = BigIntegerRange(this, other)
class BigIntegerRange(override val start: BigInteger, override val endInclusive: BigInteger) :
ClosedRange, Iterable {
override fun iterator(): Iterator {
return BigIntegerIterator(start, endInclusive)
}
}
class BigIntegerIterator(start: BigInteger, private val endInclusive: BigInteger) : Iterator {
private var current = start
override fun hasNext(): Boolean {
return current <= endInclusive
}
override fun next(): BigInteger {
return current++
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy