diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt index 3e530f0c6..5d4483a41 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt @@ -149,8 +149,12 @@ fun Decimal(value: Long) = Decimal.valueOf(value) * not guaranteed to be precise (stored as [Double]). The reason behind creation of this class, however, * is to allow infinite precision of [whole] part, while leaving [decimal] part to be rounded in inexact operations. * - * This class is value based, however, [equals] and [compareTo] are not doing *exact* comparison. Whole part is always compared - * exactly, but decimal part is considered equal if their difference is less than [EPSILON]. + * This class is value based, hence it is immutable, and can not be utilized as synchronization lock, and should not be compared + * using identity (`===`) comparison. + * + * **In general, this class is lenient about precision**, to avoid gameplay-wise player frustration, rounding is placed in multiple parts of this class, + * including its constructor (e.g. it is possible to get `Decimal.ZERO == Decimal("0.00000001")`). [EPSILON] is the reference point of precision, + * any value lesser than [EPSILON] is considered zero (including difference between *the value* and (-)1.0). */ @Suppress("unused") class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Number(), Comparable, java.io.Serializable { @@ -176,6 +180,13 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0 init { @Suppress("name_shadowing") var decimal = decimal + + if (decimal < 1.0 && decimal + EPSILON >= 1.0) { + decimal = 1.0 + } else if (decimal > -1.0 && decimal - EPSILON <= -1.0) { + decimal = -1.0 + } + @Suppress("name_shadowing") var whole = whole @@ -553,18 +564,7 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0 return false if (other is Decimal) { - return other.whole == whole && weakEqualDoubles(decimal, other.decimal) - } - - return super.equals(other) - } - - fun equalsStrict(other: Any?): Boolean { - if (isNaN) - return other is Decimal && other.isNaN // ибо hashCode() так требует - - if (other is Decimal) { - return other.whole == whole && other.decimal == decimal + return other.whole == whole && decimal == other.decimal } return super.equals(other) @@ -574,7 +574,7 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0 if (isNaN) return Double.NaN.hashCode() - return 31 * (decimal - decimal % EPSILON).hashCode() + whole.hashCode() + return 31 * decimal.hashCode() + whole.hashCode() } fun floor(): Decimal { @@ -639,36 +639,10 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0 else if (a > b) return 1 - if (other.whole == whole) { - return weakCompareDoubles(decimal, other.decimal) - } + var cmp = whole.compareTo(other.whole) + if (cmp == 0) cmp = decimal.compareTo(other.decimal) - return whole.compareTo(other.whole) - } - - fun compareToStrict(other: Decimal): Int { - if (isNaN) - return 1 - else if (other.isNaN) - return -1 - - val a = signum() - val b = other.signum() - - if (a < b) - return -1 - else if (a > b) - return 1 - - if (other.whole == whole) { - if (other.decimal == decimal) { - return 0 - } - - return if (other.decimal < decimal) 1 else -1 - } - - return whole.compareTo(other.whole) + return cmp } fun toByteArray(): ByteArray {