Much more lenient Decimal, solving much more problems than it can potentially create
This commit is contained in:
parent
419097ce88
commit
1ed2eb2134
@ -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<Decimal>, 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 {
|
||||
|
Loading…
Reference in New Issue
Block a user