/* * Copyright 2022 Stephen Tetley * * 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 decimal numbers, and its functions.////// The representation consists of both a "value" and a "scale". Standard/// equality (`==` and the `Eq` trait) consider both value and scale,/// numerical equality (are the values the same after the scales have been/// normalized) is provided by the function `numericEquals`.///pubmod BigDecimal {import java.math.BigDecimalimport java.math.RoundingModeimport java.lang.NumberFormatException////// Returns the smaller of `x` and `y`.///pubdefmin(x: BigDecimal, y: BigDecimal): BigDecimal = if (x<=y) xelsey////// Returns the larger of `x` and `y`.///pubdefmax(x: BigDecimal, y: BigDecimal): BigDecimal = if (x>=y) xelsey////// Returns the absolute value of `x`.///pubdefabs(x: BigDecimal): BigDecimal =x.abs()////// Returns `base` raised to the power of `n`.///pubdefpow(base: {base = BigDecimal}, n: Int32): BigDecimal =base#base.pow(n)////// Returns the distance between `x` and `y`.///pubdefdist(x: BigDecimal, y: BigDecimal): BigDecimal = abs(x-y)////// Returns `1` if `x > y`, `-1` if `x < y`, and `0` if `x = y`.///pubdefcompare(x: BigDecimal, y: BigDecimal): Int32 =x.compareTo(y)////// Returns `1` if `x > 0`, `-1` if `x < 0`, and `0` if `x = 0`.///pubdefsignum(x: BigDecimal): Int32 =x.signum()////// Parse the string `s` as an BigDecimal, 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[BigDecimal] = try { Some(new BigDecimal(s.strip())) } catch {case_: NumberFormatException => None }////// Returns `x` as a "plain string" without an exponent field.///pubdeftoPlainString(x: BigDecimal): String =x.toPlainString()////// Compare `x` and `y` for equality normalizing any difference in scale.///pubdefnumericEquals(x: BigDecimal, y: BigDecimal): Bool =x.compareTo(y) ==0////// Returns the scale of `x`.///pubdefscale(x: BigDecimal): Int32 =x.scale()////// Returns the precision of `x`.///pubdefprecision(x: BigDecimal): Int32 =x.precision()////// Returns `x` rounded up to a BigDecimal representing the nearest larger integer value.///pubdefceil(x: BigDecimal): BigDecimal = x.setScale(0, RoundingMode.CEILING)////// Returns `x` rounded down to a BigDecimal representing the nearest smaller integer value.///pubdeffloor(x: BigDecimal): BigDecimal = x.setScale(0, RoundingMode.FLOOR)////// Returns `x` rounded to a BigDecimal representing the nearest integer value.////// The rounding may be upwards or downwards. If the rounding up and rounding down are equally/// close, `x` will be rounded to an even value (i.e. `round(0.5ff64) == 0.0ff64`).///pubdefround(x: BigDecimal): BigDecimal = x.setScale(0, RoundingMode.HALF_EVEN)////// Convert `x` to an `Option[Int8]`.////// Returns `Some(x as Int8)` if the numeric value of `x` is within the range/// of Int8, rounding `x` towards 0`.////// Returns `None` if the numeric value of `x` is outside the range of Int8/// (i.e. -128 to 127).///pubdeftryToInt8(x: BigDecimal): Option[Int8] =tryToInt32(x) |> Option.flatMap(Int32.tryToInt8)////// Convert `x` to an `Option[Int16]`.////// Returns `Some(x as Int16)` if the numeric value of `x` is within the range/// of Int16, rounding `x` towards 0`.////// Returns `None` if the numeric value of `x` is outside the range of Int16/// (i.e. -32768 to 32767).///pubdeftryToInt16(x: BigDecimal): Option[Int16] =tryToInt32(x) |> Option.flatMap(Int32.tryToInt16)////// Convert `x` to an `Option[Int32]`.////// Returns `Some(x as Int32)` if the numeric value of `x` is within the range/// of Int32, rounding `x` towards 0`.////// Returns `None` if the numeric value of `x` is outside the range of Int32/// (i.e. -2147483648 to 2147483647).///pubdeftryToInt32(x: BigDecimal): Option[Int32] =if (x<Int32.toBigDecimal(Int32.minValue()) orx>Int32.toBigDecimal(Int32.maxValue())) Noneelse Some(x.intValue())////// Convert `x` to an `Option[Int64]`.////// Returns `Some(x as Int64)` if the numeric value of `x` is within the range/// of Int64, rounding `x` towards 0`.////// Returns `None` if the numeric value of `x` is outside the range of Int64/// (i.e. -9223372036854775808 to 9223372036854775807).///pubdeftryToInt64(x: BigDecimal): Option[Int64] =if (x<Int64.toBigDecimal(Int64.minValue()) orx>Int64.toBigDecimal(Int64.maxValue())) Noneelse Some(x.longValue())////// Convert `x` to a `BigInt`.///pubdeftoBigInt(x: BigDecimal): BigInt =x.toBigInteger()////// Convert `x` to an `Option[Float32]`.////// Returns `Some(x as Float32)` if the numeric value of `x` is within the range/// of Float32, loss of precision may occur.////// Returns `None` if the numeric value of `x` is outside the range of Float32/// (i.e. 1.4E-45 to 3.4028235E38).///pubdeftryToFloat32(x: BigDecimal): Option[Float32] =letd = x.floatValue();if (Float32.isFinite(d)) Some(d)else None////// Convert `x` to an `Option[Float64]`.////// Returns `Some(x as Float64)` if the numeric value of `x` is within the range/// of Float64, loss of precision may occur.////// Returns `None` if the numeric value of `x` is outside the range of Float64/// (i.e 4.9E-324 to 1.7976931348623157E308).///pubdeftryToFloat64(x: BigDecimal): Option[Float64] =letd = x.doubleValue();if (Float64.isFinite(d)) Some(d)else None}