Add BigDecimal implementation
This commit is contained in:
parent
efb853c1bc
commit
45eca71b3a
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2023 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decimal value with unfixed length
|
||||||
|
*
|
||||||
|
* The value is computed as `intValue*10^scale`.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public data class BigDecimal(val intValue: BigInt, val scale: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert current [BigInt] to a [BigDecimal] with scale 0.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun BigInt.asDecimal(): BigDecimal = BigDecimal(this, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A field for [BigDecimal] on top of [BigIntField]
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public object BigDecimalField : Field<BigDecimal> {
|
||||||
|
|
||||||
|
override val one: BigDecimal = BigIntField.one.asDecimal()
|
||||||
|
override val zero: BigDecimal = BigIntField.zero.asDecimal()
|
||||||
|
|
||||||
|
internal val ten: BigInt = BigIntField.number(10)
|
||||||
|
|
||||||
|
internal fun pow10(power: UInt): BigInt = ten.pow(power)
|
||||||
|
|
||||||
|
public fun Number.toDecimal(): BigDecimal = number(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rescale a [BigDecimal] to have [targetScale]. If the target scale is larger than the current scale, loss of precision is possible.
|
||||||
|
*/
|
||||||
|
public fun BigDecimal.rescale(targetScale: Int): BigDecimal = if (targetScale == scale) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
val scaleDif = scale - targetScale
|
||||||
|
if (scaleDif > 0) {
|
||||||
|
BigDecimal(BigIntField.multiply(intValue, pow10(scaleDif.toUInt())), targetScale)
|
||||||
|
} else {
|
||||||
|
BigDecimal(BigIntField.divide(intValue, pow10(abs(scaleDif).toUInt())), targetScale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun BigDecimal.pow10(power: Int): BigDecimal = BigDecimal(intValue, scale + power)
|
||||||
|
|
||||||
|
override fun add(left: BigDecimal, right: BigDecimal): BigDecimal = if (left.scale == right.scale) {
|
||||||
|
BigDecimal(BigIntField.add(left.intValue, right.intValue), left.scale)
|
||||||
|
} else {
|
||||||
|
val minScale = min(left.scale, right.scale)
|
||||||
|
//rescale both to a minimal scale
|
||||||
|
add(left.rescale(minScale), right.rescale(minScale))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun BigDecimal.unaryMinus(): BigDecimal = BigDecimal(-intValue, scale)
|
||||||
|
|
||||||
|
override fun scale(a: BigDecimal, value: Double): BigDecimal = with(BigIntField) {
|
||||||
|
BigDecimal(a.intValue * value, a.scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun divide(left: BigDecimal, right: BigDecimal): BigDecimal =
|
||||||
|
BigDecimal(BigIntField.divide(left.intValue, right.intValue), left.scale - right.scale)
|
||||||
|
|
||||||
|
override fun multiply(left: BigDecimal, right: BigDecimal): BigDecimal =
|
||||||
|
BigDecimal(BigIntField.multiply(left.intValue, right.intValue), left.scale + right.scale)
|
||||||
|
|
||||||
|
|
||||||
|
public operator fun Double.times(other: BigDecimal): BigDecimal = toDecimal() * other
|
||||||
|
|
||||||
|
public operator fun Double.div(other: BigDecimal): BigDecimal = toDecimal() / other
|
||||||
|
|
||||||
|
public operator fun Double.plus(other: BigDecimal): BigDecimal = toDecimal() + other
|
||||||
|
|
||||||
|
public operator fun Double.minus(other: BigDecimal): BigDecimal = toDecimal() - other
|
||||||
|
|
||||||
|
|
||||||
|
public operator fun BigDecimal.times(other: Double): BigDecimal = this * other.toDecimal()
|
||||||
|
|
||||||
|
public operator fun BigDecimal.div(other: Double): BigDecimal = this / other.toDecimal()
|
||||||
|
|
||||||
|
public operator fun BigDecimal.plus(other: Double): BigDecimal = this + other.toDecimal()
|
||||||
|
|
||||||
|
public operator fun BigDecimal.minus(other: Double): BigDecimal = this - other.toDecimal()
|
||||||
|
}
|
@ -16,7 +16,6 @@ import kotlin.math.min
|
|||||||
import kotlin.math.sign
|
import kotlin.math.sign
|
||||||
|
|
||||||
private typealias Magnitude = UIntArray
|
private typealias Magnitude = UIntArray
|
||||||
private typealias TBase = ULong
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
|
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
|
||||||
@ -215,6 +214,9 @@ public class BigInt internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this [BigInt] to a string using hexadecimal representation
|
||||||
|
*/
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
if (this.sign == 0.toByte()) {
|
if (this.sign == 0.toByte()) {
|
||||||
return "0x0"
|
return "0x0"
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2023 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
class BigDecimalTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simpleExpression() = with(BigDecimalField) {
|
||||||
|
assertEquals( 1000.0.toDecimal(),22.2.toDecimal().pow10(2) / 1.11)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user