ImpreciseFraction. Dear... god. There's more. Noooo!

This commit is contained in:
DBotThePony 2022-01-26 18:15:38 +07:00
parent 3313a3d011
commit a859084b6f
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -68,7 +68,7 @@ private fun bytesToLongBE(
) )
} }
const val EPSILON = 0.0000001 const val EPSILON = 0.0000000000001
private fun cmpDouble(a: Double, b: Double): Boolean { private fun cmpDouble(a: Double, b: Double): Boolean {
if (a == b) if (a == b)
@ -89,6 +89,12 @@ private val BI_DOUBLE_MIN = BigDecimal(Double.MIN_VALUE.toString()).toBigInteger
private val PERCENTAGE_CONTEXT = MathContext(6) private val PERCENTAGE_CONTEXT = MathContext(6)
private const val MEANINGFUL_BITS = 16
private const val MEANINGFUL_BITS_LONG = 1000000000000000000L
private const val MEANINGFUL_BITS_DOUBLE = MEANINGFUL_BITS_LONG.toDouble()
private val MEANINGFUL_BITS_CONTEXT = MathContext(MEANINGFUL_BITS)
private val MEANINGFUL_BITS_BI = BigInteger.valueOf(MEANINGFUL_BITS_LONG)
@Suppress("unused") @Suppress("unused")
class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Comparable<ImpreciseFraction> { class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Comparable<ImpreciseFraction> {
@JvmOverloads constructor(whole: Byte, decimal: Double = 0.0) : this(BigInteger.valueOf(whole.toLong()), decimal) @JvmOverloads constructor(whole: Byte, decimal: Double = 0.0) : this(BigInteger.valueOf(whole.toLong()), decimal)
@ -151,22 +157,61 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
val a = whole val a = whole
val c = other.whole val c = other.whole
val b = 1.0 / decimal val bZero = cmpDouble(decimal, 0.0)
val d = 1.0 / other.decimal val dZero = cmpDouble(other.decimal, 0.0)
if (bZero && dZero) {
if (isZero(a) || isZero(c))
return this
return ImpreciseFraction(a * c)
} else if (bZero) {
val d = other.decimal * MEANINGFUL_BITS_DOUBLE
val dL = d.toLong()
val adInflated = a * BigInteger.valueOf(dL)
val ad = adInflated.divideAndRemainder(MEANINGFUL_BITS_BI)
return ImpreciseFraction(
a * c + ad[0],
ad[1].toDouble() / MEANINGFUL_BITS_DOUBLE
)
} else if (dZero) {
val b = decimal * MEANINGFUL_BITS_DOUBLE
val bL = b.toLong()
val bcInflated = c * BigInteger.valueOf(bL)
val bc = bcInflated.divideAndRemainder(MEANINGFUL_BITS_BI)
return ImpreciseFraction(
a * c + bc[0],
bc[1].toDouble() / b
)
}
val b = decimal * MEANINGFUL_BITS_DOUBLE
val d = other.decimal * MEANINGFUL_BITS_DOUBLE
val bL = b.toLong() val bL = b.toLong()
val dL = d.toLong() val dL = d.toLong()
val bc = c.divideAndRemainder(BigInteger.valueOf(bL)) val bcInflated = c * BigInteger.valueOf(bL)
val ad = a.divideAndRemainder(BigInteger.valueOf(dL)) val adInflated = a * BigInteger.valueOf(dL)
val bc = bcInflated.divideAndRemainder(MEANINGFUL_BITS_BI)
val ad = adInflated.divideAndRemainder(MEANINGFUL_BITS_BI)
return ImpreciseFraction( return ImpreciseFraction(
a * c + bc[0] + ad[0], a * c + bc[0] + ad[0],
decimal * other.decimal + bc[1].toDouble() / b + ad[1].toDouble() / d decimal * other.decimal + bc[1].toDouble() / MEANINGFUL_BITS_DOUBLE + ad[1].toDouble() / MEANINGFUL_BITS_DOUBLE
) )
} }
operator fun div(other: ImpreciseFraction): ImpreciseFraction { operator fun div(other: ImpreciseFraction): ImpreciseFraction {
if (isZero && other.isZero)
return this
if (isZero(whole) && isZero(other.whole))
return ImpreciseFraction(BigInteger.ZERO, decimal / other.decimal)
val a = toBigDecmial() val a = toBigDecmial()
val b = other.toBigDecmial() val b = other.toBigDecmial()
val div = a.divideAndRemainder(b, MathContext(a.precision() + b.precision())) val div = a.divideAndRemainder(b, MathContext(a.precision() + b.precision()))
@ -240,7 +285,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
if (decimals == 0) { if (decimals == 0) {
return whole.toString() return whole.toString()
} else if (decimals > 0) { } else if (decimals > 0) {
val strDecimal = if (decimal == 0.0 || decimal == -0.0) { val strDecimal = if (decimal == 0.0 || decimal == -0.0 || decimal > 0.0 && decimal < 1E-11 || decimal < 0.0 && decimal > -1E-11) {
"0" "0"
} else if (decimal > 0.0) { } else if (decimal > 0.0) {
decimal.toString().substring(2) decimal.toString().substring(2)