/* * Copyright 2019 Liam Palmer, Magnus Madsen * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// Type of arbitrary-precision signed integers, and its functions.///pubmod BigInt {import java.math.BigDecimalimport java.math.BigIntegerimport java.lang.NumberFormatExceptionimport java.lang.ArithmeticException////// Returns the smaller of `x` and `y`.///pubdefmin(x: BigInt, y: BigInt): BigInt = if (x<=y) xelsey////// Returns the larger of `x` and `y`.///pubdefmax(x: BigInt, y: BigInt): BigInt = if (x>=y) xelsey////// Returns the absolute value of `x`.///pubdefabs(x: BigInt): BigInt = if (x>=0ii) xelse-x////// Returns `base` raised to the power of `n`.///pubdefpow(base: {base = BigInt}, n: Int32): BigInt =base#base.pow(n)////// Returns the Euclidean modulo of `x` and `n`./// The result is always non-negative.///pubdefmodulo(x: BigInt, n: BigInt): BigInt =if (n==0ii)0iielse ((x.remainder(n)) +n).remainder(n)////// Returns the remainder of `x / n`./// The result can be negative.////// See also `BigInt.modulo`.///pubdefremainder(x: BigInt, n: BigInt): BigInt =if (n==0ii)0iielsex.remainder(n)////// Returns the distance between `x` and `y`.///pubdefdist(x: BigInt, y: BigInt): BigInt = abs(x-y)////// Returns `1` if `x > y`, `-1` if `x < y`, and `0` if `x = y`.///pubdefcompare(x: BigInt, y: BigInt): Int32 = {if (x==y)0elseif (x<y) -1else1 }////// Returns `1` if `x > 0`, `-1` if `x < 0`, and `0` if `x = 0`.///pubdefsignum(x: BigInt): Int32 = compare(x, 0ii)////// Returns the bit of `x` at `position` (either 0 or 1).////// The bits of x have positions: 0 (rightmost bit), 1, 2, ...///pubdefgetBit(x: BigInt, position: Int32): Int32 =if (rightShift(x, position) `remainder`2ii==0ii) 0else1////// Returns the greatest common non-negative divisor of `x` and `y`.///pubdefgcd(x: BigInt, y: BigInt): BigInt = if (y==0ii) abs(x) elsegcd(y, x`remainder`y)////// Returns `x` with the bit at position `position` set (to 1).///pubdefsetBit(x: BigInt, position: Int32): BigInt = bitwiseOr(x, leftShift(1ii, position))////// Returns `x` with the bit at position `position` cleared (to 0).///pubdefclearBit(x: BigInt, position: Int32): BigInt = bitwiseAnd(x, bitwiseNot(leftShift(1ii, position)))////// Returns `x` with the bit at position `position` flipped.///pubdefflipBit(x: BigInt, position: Int32): BigInt = bitwiseXor(x, leftShift(1ii, position))////// Returns the integer binary logarithm of `x`.///pubdeflog2(x: BigInt): Int32 =x.bitLength()////// Returns `x` with the bits shifted left by `y` places///pubdefleftShift(x: BigInt, y: Int32): BigInt =x.shiftLeft(y)////// Returns `x` with the bits shifted right by `y` places///pubdefrightShift(x: BigInt, y: Int32): BigInt =x.shiftRight(y)////// Returns the bitwise AND of `x` and `y`.///pubdefbitwiseAnd(x: BigInt, y: BigInt): BigInt =x.$and(y)////// Returns the bitwise NOT of `x`.///pubdefbitwiseNot(x: BigInt): BigInt =x.$not()////// Returns the bitwise OR of `x` and `y`.///pubdefbitwiseOr(x: BigInt, y: BigInt): BigInt =x.$or(y)////// Returns the bitwise XOR of `x` and `y`.///pubdefbitwiseXor(x: BigInt, y: BigInt): BigInt =x.$xor(y)////// Return a string representation of `x`.///pubdeftoString(x: BigInt): String = ToString.toString(x)////// Parse the string `s` as an BigInt, leading or trailing whitespace is trimmed./// A successful parse is wrapped with `Some(x)`, a parse failure is indicated by `None`.///pubdeffromString(s: String): Option[BigInt] = try { Some(new BigInteger(s.strip())) } catch {case_: NumberFormatException => None }////// Convert `x` to an `Option[Int8]`.////// Returns `Some(x as Int8)` if the numeric value of `x` can be represented exactly.////// Returns `None` if the numeric value of `x` is outside the range of Int8/// (i.e. -128 to 127).///pubdeftryToInt8(x: BigInt): Option[Int8] =try { Some(x.byteValueExact()) } catch {case_: ArithmeticException => None }////// Convert `x` to an `Option[Int16]`.////// Returns `Some(x as Int16)` if the numeric value of `x` can be represented exactly.////// Returns `None` if the numeric value of `x` is outside the range of Int16/// (i.e. -32768 to 32767).///pubdeftryToInt16(x: BigInt): Option[Int16] =try { Some(x.shortValueExact()) } catch {case_: ArithmeticException => None }////// Convert `x` to an `Option[Int32]`.////// Returns `Some(x as Int32)` if the numeric value of `x` can be represented exactly.////// Returns `None` if the numeric value of `x` is outside the range of Int32/// (i.e. -2147483648 to 2147483647).///pubdeftryToInt32(x: BigInt): Option[Int32] =try { Some(x.intValueExact()) } catch {case_: ArithmeticException => None }////// Convert `x` to an `Option[Int64]`.////// Returns `Some(x as Int64)` if the numeric value of `x` can be represented exactly.////// Returns `None` if the numeric value of `x` is outside the range of Int64/// (i.e. -9223372036854775808 to 9223372036854775807).///pubdeftryToInt64(x: BigInt): Option[Int64] =try { Some(x.longValueExact()) } catch {case_: ArithmeticException => None }////// Convert `x` to an `Option[Float32]`.////// Returns `Some(x as Float32)` if the numeric value of `x` is within the range of Float32.////// Warning: even if `x` is in the range of Float32 it may lose precision.////// Returns `None` if the numeric value of `x` is outside the range of Float32/// (i.e. 1.4E-45 to 3.4028235E38).///pubdeftryToFloat32(x: BigInt): Option[Float32] =letxd = new BigDecimal(x);letd = xd.floatValue();forM (f32min <- Float32.tryToBigInt(Float32.minValue());f32max <- Float32.tryToBigInt(Float32.maxValue());iff32min<=xandx<=f32max ) yieldd////// Convert `x` to an `Option[Float64]`.////// Returns `Some(x as Float64)` if the numeric value of `x` is within the range of Float32.////// Warning: even if `x` is in the range of Float64 it may lose precision.////// Returns `None` if the numeric value of `x` is outside the range of Float64/// (i.e 4.9E-324 to 1.7976931348623157E308).///pubdeftryToFloat64(x: BigInt): Option[Float64] =letxd = new BigDecimal(x);letd = xd.doubleValue();forM (f64min <- Float64.tryToBigInt(Float64.minValue());f64max <- Float64.tryToBigInt(Float64.maxValue());iff64min<=xandx<=f64max ) yieldd////// Convert `x` to an `BigDecimal`.///pubdeftoBigDecimal(x: BigInt): BigDecimal =new BigDecimal(x)////// Helper function for the `clamp` conversion functions.///defclamp(min: {min = BigInt}, max: {max = BigInt}, x: BigInt): BigInt =if (x<min#min)min#minelseif (x>max#max)max#maxelsex////// Convert `x` to an `Int8`.////// Returns `x` clamped within the Int8 range `min` to `max`.///pubdefclampToInt8(min: {min = Int8}, max: {max = Int8}, x: BigInt): Int8 =letminii = Int8.toBigInt(min#min);letmaxii = Int8.toBigInt(max#max);try {lety = clamp(min = minii, max = maxii, x);y.byteValueExact() } catch {// This should be impossible!case_: ArithmeticException => min#min }////// Convert `x` to an `Int16`.////// Returns `x` clamped within the Int16 range `min` to `max`.///pubdefclampToInt16(min: {min = Int16}, max: {max = Int16}, x: BigInt): Int16 =letminii = Int16.toBigInt(min#min);letmaxii = Int16.toBigInt(max#max);try {lety = clamp(min = minii, max = maxii, x);y.shortValueExact() } catch {// This should be impossible!case_: ArithmeticException => min#min }////// Convert `x` to an `Int32`.////// Returns `x` clamped within the Int32 range `min` to `max`.///pubdefclampToInt32(min: {min = Int32}, max: {max = Int32}, x: BigInt): Int32 =letminii = Int32.toBigInt(min#min);letmaxii = Int32.toBigInt(max#max);try {lety = clamp(min = minii, max = maxii, x);y.intValueExact() } catch {// This should be impossible!case_: ArithmeticException => min#min }////// Convert `x` to an `Int64`.////// Returns `x` clamped within the Int64 range `min` to `max`.///pubdefclampToInt64(min: {min = Int64}, max: {max = Int64}, x: BigInt): Int64 =letminii = Int64.toBigInt(min#min);letmaxii = Int64.toBigInt(max#max);try {lety = clamp(min = minii, max = maxii, x);y.longValueExact() } catch {// This should be impossible!case_: ArithmeticException => min#min }////// Convert `x` to a `Float32`.////// Returns `x` clamped within the Float32 range `min` to `max`.///pubdefclampToFloat32(min: {min = Float32}, max: {max = Float32}, x: BigInt): Float32 =letstep = () -> {forM (f32min <- Float32.tryToBigInt(min#min);f32max <- Float32.tryToBigInt(max#max) ) yield {letx1 = clamp(min = f32min, max = f32max, x);letxd = new BigDecimal(x1);xd.floatValue() } };matchstep() {case None => Float32.nan()case Some(d) => d }////// Convert `x` to a `Float64`.////// Returns `x` clamped within the Float64 range `min` to `max`.///pubdefclampToFloat64(min: {min = Float64}, max: {max = Float64}, x: BigInt): Float64 =letstep = () -> {forM (f64min <- Float64.tryToBigInt(min#min);f64max <- Float64.tryToBigInt(max#max) ) yield {letx1 = clamp(min = f64min, max = f64max, x);letxd = new BigDecimal(x1);xd.doubleValue() } };matchstep() {case None => Float64.nan()case Some(d) => d }}