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,
|
* 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.
|
* 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
|
* This class is value based, hence it is immutable, and can not be utilized as synchronization lock, and should not be compared
|
||||||
* exactly, but decimal part is considered equal if their difference is less than [EPSILON].
|
* 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")
|
@Suppress("unused")
|
||||||
class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Number(), Comparable<Decimal>, java.io.Serializable {
|
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 {
|
init {
|
||||||
@Suppress("name_shadowing")
|
@Suppress("name_shadowing")
|
||||||
var decimal = decimal
|
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")
|
@Suppress("name_shadowing")
|
||||||
var whole = whole
|
var whole = whole
|
||||||
|
|
||||||
@ -553,18 +564,7 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
if (other is Decimal) {
|
if (other is Decimal) {
|
||||||
return other.whole == whole && weakEqualDoubles(decimal, other.decimal)
|
return other.whole == whole && 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 super.equals(other)
|
return super.equals(other)
|
||||||
@ -574,7 +574,7 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0
|
|||||||
if (isNaN)
|
if (isNaN)
|
||||||
return Double.NaN.hashCode()
|
return Double.NaN.hashCode()
|
||||||
|
|
||||||
return 31 * (decimal - decimal % EPSILON).hashCode() + whole.hashCode()
|
return 31 * decimal.hashCode() + whole.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun floor(): Decimal {
|
fun floor(): Decimal {
|
||||||
@ -639,36 +639,10 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0
|
|||||||
else if (a > b)
|
else if (a > b)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if (other.whole == whole) {
|
var cmp = whole.compareTo(other.whole)
|
||||||
return weakCompareDoubles(decimal, other.decimal)
|
if (cmp == 0) cmp = decimal.compareTo(other.decimal)
|
||||||
}
|
|
||||||
|
|
||||||
return whole.compareTo(other.whole)
|
return cmp
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toByteArray(): ByteArray {
|
fun toByteArray(): ByteArray {
|
||||||
|
Loading…
Reference in New Issue
Block a user