diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt index 900b462cc..5d65c2f50 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt @@ -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 { 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 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") class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Comparable { @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 c = other.whole - val b = 1.0 / decimal - val d = 1.0 / other.decimal + val bZero = cmpDouble(decimal, 0.0) + 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 dL = d.toLong() - val bc = c.divideAndRemainder(BigInteger.valueOf(bL)) - val ad = a.divideAndRemainder(BigInteger.valueOf(dL)) + val bcInflated = c * BigInteger.valueOf(bL) + val adInflated = a * BigInteger.valueOf(dL) + + val bc = bcInflated.divideAndRemainder(MEANINGFUL_BITS_BI) + val ad = adInflated.divideAndRemainder(MEANINGFUL_BITS_BI) return ImpreciseFraction( 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 { + if (isZero && other.isZero) + return this + + if (isZero(whole) && isZero(other.whole)) + return ImpreciseFraction(BigInteger.ZERO, decimal / other.decimal) + val a = toBigDecmial() val b = other.toBigDecmial() 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) { return whole.toString() } 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" } else if (decimal > 0.0) { decimal.toString().substring(2)