Remove Fraction class

This commit is contained in:
DBotThePony 2023-01-14 10:05:42 +07:00
parent 5149b7432d
commit ce437d4e14
Signed by: DBot
GPG Key ID: DCC23B5715498507
5 changed files with 1 additions and 1343 deletions

View File

@ -729,18 +729,6 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0
return toInt().toShort()
}
fun toFraction(): Fraction {
if (isZero) {
return Fraction.ZERO
}
if (weakEqualDoubles(decimal, 0.0)) {
return Fraction(whole)
}
return Fraction(toBigDecmial())
}
fun percentage(divisor: Decimal, zeroing: Boolean = true): Float {
if ((isZero || divisor.isZero) && zeroing) return 0f
if (isNaN || divisor.isNaN || divisor.isZero) return Float.NaN

View File

@ -59,19 +59,6 @@ fun Number.dynPlus(other: Number): Number {
is Int, is Byte, is Short -> this + other.toInt()
is Long -> this + other.toLong()
is Decimal -> this + other
is Fraction -> this + other.toImpreciseFraction()
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
is Fraction -> {
when (other) {
is Float -> this + other.toFloat()
is Double -> this + other.toDouble()
is Int, is Byte, is Short -> this + other.toInt()
is Long -> this + other.toLong()
is Decimal -> this + other.toFraction()
is Fraction -> this + other
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
@ -101,19 +88,6 @@ fun Number.dynMinus(other: Number): Number {
is Int, is Byte, is Short -> this - other.toInt()
is Long -> this - other.toLong()
is Decimal -> this - other
is Fraction -> this - other.toImpreciseFraction()
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
is Fraction -> {
when (other) {
is Float -> this - other.toFloat()
is Double -> this - other.toDouble()
is Int, is Byte, is Short -> this - other.toInt()
is Long -> this - other.toLong()
is Decimal -> this - other.toFraction()
is Fraction -> this - other
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
@ -143,19 +117,6 @@ fun Number.dynTimes(other: Number): Number {
is Int, is Byte, is Short -> this * other.toInt()
is Long -> this * other.toLong()
is Decimal -> this * other
is Fraction -> this * other.toImpreciseFraction()
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
is Fraction -> {
when (other) {
is Float -> this * other.toFloat()
is Double -> this * other.toDouble()
is Int, is Byte, is Short -> this * other.toInt()
is Long -> this * other.toLong()
is Decimal -> this * other.toFraction()
is Fraction -> this * other
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
@ -185,19 +146,6 @@ fun Number.dynDiv(other: Number): Number {
is Int, is Byte, is Short -> this / other.toInt()
is Long -> this / other.toLong()
is Decimal -> this / other
is Fraction -> this / other.toImpreciseFraction()
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
is Fraction -> {
when (other) {
is Float -> this / other.toFloat()
is Double -> this / other.toDouble()
is Int, is Byte, is Short -> this / other.toInt()
is Long -> this / other.toLong()
is Decimal -> this / other.toFraction()
is Fraction -> this / other
else -> throw IllegalStateException("I don't know what to do with ${other::class.qualifiedName} (right hand operand)")
}
}
@ -206,7 +154,7 @@ fun Number.dynDiv(other: Number): Number {
}
}
val Number.isFractional get() = this is Float || this is Double || this is Decimal || this is Fraction
val Number.isFractional get() = this is Float || this is Double || this is Decimal
val Number.isWhole get() = !isFractional
fun Number.toDecimal(): Decimal {
@ -218,7 +166,6 @@ fun Number.toDecimal(): Decimal {
is Byte -> Decimal(this)
is Short -> Decimal(this)
is Long -> Decimal(this)
is Fraction -> this.toImpreciseFraction()
else -> throw ClassCastException("Can not turn $this into ImpreciseFraction")
}
}

View File

@ -87,7 +87,6 @@ enum class SiPrefix(
}
val decimal = BigDecimal(string)
val fraction = Fraction(decimal)
val impreciseFraction = Decimal(string)
val integer = if (!fractional) BigInteger(string) else null

View File

@ -1,931 +0,0 @@
package ru.dbotthepony.mc.otm.core
import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import org.apache.logging.log4j.LogManager
import java.math.BigDecimal
import java.math.BigInteger
import java.math.MathContext
import java.math.RoundingMode
private fun powScale(int: Int): BigInteger {
if (int <= 0)
return BigInteger.ONE
var result = BigInteger.TEN
for (i in 2 .. int)
result *= BigInteger.TEN
return result
}
private fun powUnscaled(unscaled: BigInteger, scale: Int): BigInteger {
if (scale >= 0)
return unscaled
var result = unscaled
for (i in 2 .. -scale)
result *= BigInteger.TEN
return result
}
val DEFAULT_MATH_CONTEXT = MathContext(64, RoundingMode.HALF_UP)
@Suppress("NOTHING_TO_INLINE")
private inline fun invertCompare(int: Int): Int {
if (int == 0)
return 0
return if (int < 0) 1 else -1
}
private val BI_MINUS_ZERO = BigInteger("-0")
private val BI_MINUS_ONE = BigInteger("-1")
private val BI_DIV = BigInteger.valueOf(1_000_000_000)
private val BI_DIV2 = BigInteger.valueOf(10)
private val BI_MINUS_DIV = BigInteger.valueOf(-1_000_000_000)
private fun isZero(value: BigInteger): Boolean {
return when (value.signum()) {
0 -> true
1 -> value == BigInteger.ZERO
-1 -> value == BI_MINUS_ZERO
else -> false
}
}
private fun isOne(value: BigInteger): Boolean {
return when (value.signum()) {
0 -> false
1 -> value == BigInteger.ONE
-1 -> value == BI_MINUS_ONE
else -> false
}
}
private fun compactTwoMod(value1: BigInteger, value2: BigInteger, compact: Boolean = true): Fraction {
val mod = value1.divideAndRemainder(value2)
if (isZero(mod[1]))
return Fraction(mod[0], compact = compact)
return Fraction(value1, value2, compact = compact)
}
private fun positive(value: BigInteger): BigInteger {
return when (value.signum()) {
0 -> value
1 -> value
-1 -> -value
else -> throw InternalError()
}
}
private val GCDs = arrayOf(
BigInteger.valueOf(2), BigInteger.valueOf(3), BigInteger.valueOf(5), BigInteger.valueOf(7), BigInteger.valueOf(11), BigInteger.valueOf(13), BigInteger.valueOf(17), BigInteger.valueOf(19), BigInteger.valueOf(23), BigInteger.valueOf(29), BigInteger.valueOf(31), BigInteger.valueOf(37), BigInteger.valueOf(41), BigInteger.valueOf(43), BigInteger.valueOf(47), BigInteger.valueOf(53), BigInteger.valueOf(59), BigInteger.valueOf(61), BigInteger.valueOf(67), BigInteger.valueOf(71),
BigInteger.valueOf(73), BigInteger.valueOf(79), BigInteger.valueOf(83), BigInteger.valueOf(89), BigInteger.valueOf(97), BigInteger.valueOf(101), BigInteger.valueOf(103), BigInteger.valueOf(107), BigInteger.valueOf(109), BigInteger.valueOf(113), BigInteger.valueOf(127), BigInteger.valueOf(131), BigInteger.valueOf(137), BigInteger.valueOf(139), BigInteger.valueOf(149), BigInteger.valueOf(151), BigInteger.valueOf(157), BigInteger.valueOf(163), BigInteger.valueOf(167), BigInteger.valueOf(173),
BigInteger.valueOf(179), BigInteger.valueOf(181), BigInteger.valueOf(191), BigInteger.valueOf(193), BigInteger.valueOf(197), BigInteger.valueOf(199), BigInteger.valueOf(211), BigInteger.valueOf(223), BigInteger.valueOf(227), BigInteger.valueOf(229), BigInteger.valueOf(233), BigInteger.valueOf(239), BigInteger.valueOf(241), BigInteger.valueOf(251), BigInteger.valueOf(257), BigInteger.valueOf(263), BigInteger.valueOf(269), BigInteger.valueOf(271), BigInteger.valueOf(277), BigInteger.valueOf(281),
BigInteger.valueOf(283), BigInteger.valueOf(293), BigInteger.valueOf(307), BigInteger.valueOf(311), BigInteger.valueOf(313), BigInteger.valueOf(317), BigInteger.valueOf(331), BigInteger.valueOf(337), BigInteger.valueOf(347), BigInteger.valueOf(349), BigInteger.valueOf(353), BigInteger.valueOf(359), BigInteger.valueOf(367), BigInteger.valueOf(373), BigInteger.valueOf(379), BigInteger.valueOf(383), BigInteger.valueOf(389), BigInteger.valueOf(397), BigInteger.valueOf(401), BigInteger.valueOf(409),
BigInteger.valueOf(419), BigInteger.valueOf(421), BigInteger.valueOf(431), BigInteger.valueOf(433), BigInteger.valueOf(439), BigInteger.valueOf(443), BigInteger.valueOf(449), BigInteger.valueOf(457), BigInteger.valueOf(461), BigInteger.valueOf(463), BigInteger.valueOf(467), BigInteger.valueOf(479), BigInteger.valueOf(487), BigInteger.valueOf(491), BigInteger.valueOf(499), BigInteger.valueOf(503), BigInteger.valueOf(509), BigInteger.valueOf(521), BigInteger.valueOf(523), BigInteger.valueOf(541),
BigInteger.valueOf(547), BigInteger.valueOf(557), BigInteger.valueOf(563), BigInteger.valueOf(569), BigInteger.valueOf(571), BigInteger.valueOf(577), BigInteger.valueOf(587), BigInteger.valueOf(593), BigInteger.valueOf(599), BigInteger.valueOf(601), BigInteger.valueOf(607), BigInteger.valueOf(613), BigInteger.valueOf(617), BigInteger.valueOf(619), BigInteger.valueOf(631), BigInteger.valueOf(641), BigInteger.valueOf(643), BigInteger.valueOf(647), BigInteger.valueOf(653), BigInteger.valueOf(659),
BigInteger.valueOf(661), BigInteger.valueOf(673), BigInteger.valueOf(677), BigInteger.valueOf(683), BigInteger.valueOf(691), BigInteger.valueOf(701), BigInteger.valueOf(709), BigInteger.valueOf(719), BigInteger.valueOf(727), BigInteger.valueOf(733), BigInteger.valueOf(739), BigInteger.valueOf(743), BigInteger.valueOf(751), BigInteger.valueOf(757), BigInteger.valueOf(761), BigInteger.valueOf(769), BigInteger.valueOf(773), BigInteger.valueOf(787), BigInteger.valueOf(797), BigInteger.valueOf(809),
BigInteger.valueOf(811), BigInteger.valueOf(821), BigInteger.valueOf(823), BigInteger.valueOf(827), BigInteger.valueOf(829), BigInteger.valueOf(839), BigInteger.valueOf(853), BigInteger.valueOf(857), BigInteger.valueOf(859), BigInteger.valueOf(863), BigInteger.valueOf(877), BigInteger.valueOf(881), BigInteger.valueOf(883), BigInteger.valueOf(887), BigInteger.valueOf(907), BigInteger.valueOf(911), BigInteger.valueOf(919), BigInteger.valueOf(929), BigInteger.valueOf(937), BigInteger.valueOf(941),
BigInteger.valueOf(947), BigInteger.valueOf(953), BigInteger.valueOf(967), BigInteger.valueOf(971), BigInteger.valueOf(977), BigInteger.valueOf(983), BigInteger.valueOf(991), BigInteger.valueOf(997), BigInteger.valueOf(1009), BigInteger.valueOf(1013), BigInteger.valueOf(1019), BigInteger.valueOf(1021), BigInteger.valueOf(1031), BigInteger.valueOf(1033), BigInteger.valueOf(1039), BigInteger.valueOf(1049), BigInteger.valueOf(1051), BigInteger.valueOf(1061), BigInteger.valueOf(1063), BigInteger.valueOf(1069),
BigInteger.valueOf(1087), BigInteger.valueOf(1091), BigInteger.valueOf(1093), BigInteger.valueOf(1097), BigInteger.valueOf(1103), BigInteger.valueOf(1109), BigInteger.valueOf(1117), BigInteger.valueOf(1123), BigInteger.valueOf(1129), BigInteger.valueOf(1151), BigInteger.valueOf(1153), BigInteger.valueOf(1163), BigInteger.valueOf(1171), BigInteger.valueOf(1181), BigInteger.valueOf(1187), BigInteger.valueOf(1193), BigInteger.valueOf(1201), BigInteger.valueOf(1213), BigInteger.valueOf(1217), BigInteger.valueOf(1223),
BigInteger.valueOf(1229), BigInteger.valueOf(1231), BigInteger.valueOf(1237), BigInteger.valueOf(1249), BigInteger.valueOf(1259), BigInteger.valueOf(1277), BigInteger.valueOf(1279), BigInteger.valueOf(1283), BigInteger.valueOf(1289), BigInteger.valueOf(1291), BigInteger.valueOf(1297), BigInteger.valueOf(1301), BigInteger.valueOf(1303), BigInteger.valueOf(1307), BigInteger.valueOf(1319), BigInteger.valueOf(1321), BigInteger.valueOf(1327), BigInteger.valueOf(1361), BigInteger.valueOf(1367), BigInteger.valueOf(1373),
BigInteger.valueOf(1381), BigInteger.valueOf(1399), BigInteger.valueOf(1409), BigInteger.valueOf(1423), BigInteger.valueOf(1427), BigInteger.valueOf(1429), BigInteger.valueOf(1433), BigInteger.valueOf(1439), BigInteger.valueOf(1447), BigInteger.valueOf(1451), BigInteger.valueOf(1453), BigInteger.valueOf(1459), BigInteger.valueOf(1471), BigInteger.valueOf(1481), BigInteger.valueOf(1483), BigInteger.valueOf(1487), BigInteger.valueOf(1489), BigInteger.valueOf(1493), BigInteger.valueOf(1499), BigInteger.valueOf(1511),
BigInteger.valueOf(1523), BigInteger.valueOf(1531), BigInteger.valueOf(1543), BigInteger.valueOf(1549), BigInteger.valueOf(1553), BigInteger.valueOf(1559), BigInteger.valueOf(1567), BigInteger.valueOf(1571), BigInteger.valueOf(1579), BigInteger.valueOf(1583), BigInteger.valueOf(1597), BigInteger.valueOf(1601), BigInteger.valueOf(1607), BigInteger.valueOf(1609), BigInteger.valueOf(1613), BigInteger.valueOf(1619), BigInteger.valueOf(1621), BigInteger.valueOf(1627), BigInteger.valueOf(1637), BigInteger.valueOf(1657),
BigInteger.valueOf(1663), BigInteger.valueOf(1667), BigInteger.valueOf(1669), BigInteger.valueOf(1693), BigInteger.valueOf(1697), BigInteger.valueOf(1699), BigInteger.valueOf(1709), BigInteger.valueOf(1721), BigInteger.valueOf(1723), BigInteger.valueOf(1733), BigInteger.valueOf(1741), BigInteger.valueOf(1747), BigInteger.valueOf(1753), BigInteger.valueOf(1759), BigInteger.valueOf(1777), BigInteger.valueOf(1783), BigInteger.valueOf(1787), BigInteger.valueOf(1789), BigInteger.valueOf(1801), BigInteger.valueOf(1811),
BigInteger.valueOf(1823), BigInteger.valueOf(1831), BigInteger.valueOf(1847), BigInteger.valueOf(1861), BigInteger.valueOf(1867), BigInteger.valueOf(1871), BigInteger.valueOf(1873), BigInteger.valueOf(1877), BigInteger.valueOf(1879), BigInteger.valueOf(1889), BigInteger.valueOf(1901), BigInteger.valueOf(1907), BigInteger.valueOf(1913), BigInteger.valueOf(1931), BigInteger.valueOf(1933), BigInteger.valueOf(1949), BigInteger.valueOf(1951), BigInteger.valueOf(1973), BigInteger.valueOf(1979), BigInteger.valueOf(1987),
BigInteger.valueOf(1993), BigInteger.valueOf(1997), BigInteger.valueOf(1999), BigInteger.valueOf(2003), BigInteger.valueOf(2011), BigInteger.valueOf(2017), BigInteger.valueOf(2027), BigInteger.valueOf(2029), BigInteger.valueOf(2039), BigInteger.valueOf(2053), BigInteger.valueOf(2063), BigInteger.valueOf(2069), BigInteger.valueOf(2081), BigInteger.valueOf(2083), BigInteger.valueOf(2087), BigInteger.valueOf(2089), BigInteger.valueOf(2099), BigInteger.valueOf(2111), BigInteger.valueOf(2113), BigInteger.valueOf(2129),
BigInteger.valueOf(2131), BigInteger.valueOf(2137), BigInteger.valueOf(2141), BigInteger.valueOf(2143), BigInteger.valueOf(2153), BigInteger.valueOf(2161), BigInteger.valueOf(2179), BigInteger.valueOf(2203), BigInteger.valueOf(2207), BigInteger.valueOf(2213), BigInteger.valueOf(2221), BigInteger.valueOf(2237), BigInteger.valueOf(2239), BigInteger.valueOf(2243), BigInteger.valueOf(2251), BigInteger.valueOf(2267), BigInteger.valueOf(2269), BigInteger.valueOf(2273), BigInteger.valueOf(2281), BigInteger.valueOf(2287),
BigInteger.valueOf(2293), BigInteger.valueOf(2297), BigInteger.valueOf(2309), BigInteger.valueOf(2311), BigInteger.valueOf(2333), BigInteger.valueOf(2339), BigInteger.valueOf(2341), BigInteger.valueOf(2347), BigInteger.valueOf(2351), BigInteger.valueOf(2357), BigInteger.valueOf(2371), BigInteger.valueOf(2377), BigInteger.valueOf(2381), BigInteger.valueOf(2383), BigInteger.valueOf(2389), BigInteger.valueOf(2393), BigInteger.valueOf(2399), BigInteger.valueOf(2411), BigInteger.valueOf(2417), BigInteger.valueOf(2423),
BigInteger.valueOf(2437), BigInteger.valueOf(2441), BigInteger.valueOf(2447), BigInteger.valueOf(2459), BigInteger.valueOf(2467), BigInteger.valueOf(2473), BigInteger.valueOf(2477), BigInteger.valueOf(2503), BigInteger.valueOf(2521), BigInteger.valueOf(2531), BigInteger.valueOf(2539), BigInteger.valueOf(2543), BigInteger.valueOf(2549), BigInteger.valueOf(2551), BigInteger.valueOf(2557), BigInteger.valueOf(2579), BigInteger.valueOf(2591), BigInteger.valueOf(2593), BigInteger.valueOf(2609), BigInteger.valueOf(2617),
BigInteger.valueOf(2621), BigInteger.valueOf(2633), BigInteger.valueOf(2647), BigInteger.valueOf(2657), BigInteger.valueOf(2659), BigInteger.valueOf(2663), BigInteger.valueOf(2671), BigInteger.valueOf(2677), BigInteger.valueOf(2683), BigInteger.valueOf(2687), BigInteger.valueOf(2689), BigInteger.valueOf(2693), BigInteger.valueOf(2699), BigInteger.valueOf(2707), BigInteger.valueOf(2711), BigInteger.valueOf(2713), BigInteger.valueOf(2719), BigInteger.valueOf(2729), BigInteger.valueOf(2731), BigInteger.valueOf(2741),
BigInteger.valueOf(2749), BigInteger.valueOf(2753), BigInteger.valueOf(2767), BigInteger.valueOf(2777), BigInteger.valueOf(2789), BigInteger.valueOf(2791), BigInteger.valueOf(2797), BigInteger.valueOf(2801), BigInteger.valueOf(2803), BigInteger.valueOf(2819), BigInteger.valueOf(2833), BigInteger.valueOf(2837), BigInteger.valueOf(2843), BigInteger.valueOf(2851), BigInteger.valueOf(2857), BigInteger.valueOf(2861), BigInteger.valueOf(2879), BigInteger.valueOf(2887), BigInteger.valueOf(2897), BigInteger.valueOf(2903),
BigInteger.valueOf(2909), BigInteger.valueOf(2917), BigInteger.valueOf(2927), BigInteger.valueOf(2939), BigInteger.valueOf(2953), BigInteger.valueOf(2957), BigInteger.valueOf(2963), BigInteger.valueOf(2969), BigInteger.valueOf(2971), BigInteger.valueOf(2999), BigInteger.valueOf(3001), BigInteger.valueOf(3011), BigInteger.valueOf(3019), BigInteger.valueOf(3023), BigInteger.valueOf(3037), BigInteger.valueOf(3041), BigInteger.valueOf(3049), BigInteger.valueOf(3061), BigInteger.valueOf(3067), BigInteger.valueOf(3079),
BigInteger.valueOf(3083), BigInteger.valueOf(3089), BigInteger.valueOf(3109), BigInteger.valueOf(3119), BigInteger.valueOf(3121), BigInteger.valueOf(3137), BigInteger.valueOf(3163), BigInteger.valueOf(3167), BigInteger.valueOf(3169), BigInteger.valueOf(3181), BigInteger.valueOf(3187), BigInteger.valueOf(3191), BigInteger.valueOf(3203), BigInteger.valueOf(3209), BigInteger.valueOf(3217), BigInteger.valueOf(3221), BigInteger.valueOf(3229), BigInteger.valueOf(3251), BigInteger.valueOf(3253), BigInteger.valueOf(3257),
BigInteger.valueOf(3259), BigInteger.valueOf(3271), BigInteger.valueOf(3299), BigInteger.valueOf(3301), BigInteger.valueOf(3307), BigInteger.valueOf(3313), BigInteger.valueOf(3319), BigInteger.valueOf(3323), BigInteger.valueOf(3329), BigInteger.valueOf(3331), BigInteger.valueOf(3343), BigInteger.valueOf(3347), BigInteger.valueOf(3359), BigInteger.valueOf(3361), BigInteger.valueOf(3371), BigInteger.valueOf(3373), BigInteger.valueOf(3389), BigInteger.valueOf(3391), BigInteger.valueOf(3407), BigInteger.valueOf(3413),
BigInteger.valueOf(3433), BigInteger.valueOf(3449), BigInteger.valueOf(3457), BigInteger.valueOf(3461), BigInteger.valueOf(3463), BigInteger.valueOf(3467), BigInteger.valueOf(3469), BigInteger.valueOf(3491), BigInteger.valueOf(3499), BigInteger.valueOf(3511), BigInteger.valueOf(3517), BigInteger.valueOf(3527), BigInteger.valueOf(3529), BigInteger.valueOf(3533), BigInteger.valueOf(3539), BigInteger.valueOf(3541), BigInteger.valueOf(3547), BigInteger.valueOf(3557), BigInteger.valueOf(3559), BigInteger.valueOf(3571),
)
private val COMPACT_THRESHOLD = BigInteger("1000000000000000000000")
@Suppress("NAME_SHADOWING")
private fun compactTwo(value1: BigInteger, value2: BigInteger, compact: Boolean = true): Fraction {
when (value1.signum()) {
0 -> return Fraction(value1, value2, compact = compact)
1 -> if (value1 < BI_DIV) return compactTwoMod(value1, value2, compact)
-1 -> if (value1 > BI_MINUS_DIV) return compactTwoMod(value1, value2, compact)
}
when (value2.signum()) {
0 -> return Fraction(value1, value2, compact = compact)
1 -> if (value2 < BI_DIV) return compactTwoMod(value1, value2, compact)
-1 -> if (value2 > BI_MINUS_DIV) return compactTwoMod(value1, value2, compact)
}
var value1 = value1
var value2 = value2
while (true) {
val _a = value1.divideAndRemainder(BI_DIV)
val _b = value2.divideAndRemainder(BI_DIV)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
}
while (true) {
val _a = value1.divideAndRemainder(BI_DIV2)
val _b = value2.divideAndRemainder(BI_DIV2)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
}
val p1 = positive(value1)
val p2 = positive(value2)
if (p1 > COMPACT_THRESHOLD || p2 > COMPACT_THRESHOLD) {
var hit = true
while (hit) {
hit = false
for (i in GCDs.size - 1 downTo 0) {
val div = GCDs[i]
while (true) {
val _a = value1.divideAndRemainder(div)
val _b = value2.divideAndRemainder(div)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
hit = true
}
}
}
} else if (p1 > GCDs[0] && p2 > GCDs[0]) {
var hit = true
while (hit) {
hit = false
for (i in 4 downTo 0) {
val div = GCDs[i]
while (true) {
val _a = value1.divideAndRemainder(div)
val _b = value2.divideAndRemainder(div)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
hit = true
}
}
}
}
return compactTwoMod(value1, value2, compact)
}
private fun unsignedInt(value: Byte): Int {
if (value < 0) {
return 256 + value
}
return value.toInt()
}
private data class MagnitudeCrunchResult(val value: BigInteger, val mag: Int)
@Suppress("NAME_SHADOWING")
private fun magnitude(value: BigInteger): MagnitudeCrunchResult {
if (isZero(value))
return MagnitudeCrunchResult(value, 0)
var mag = 0
var value = value
while (true) {
val c = value.divideAndRemainder(BI_DIV2)
if (!isZero(c[1]))
break
value = c[0]
mag++
}
return MagnitudeCrunchResult(value, mag)
}
@Suppress("unused")
class Fraction @JvmOverloads constructor(
val value: BigInteger,
val divisor: BigInteger = BigInteger.ONE,
val compact: Boolean = true
) : Number(), Comparable<Fraction> {
@JvmOverloads constructor(value: Long, compact: Boolean = true) : this(BigInteger.valueOf(value), compact = compact)
@JvmOverloads constructor(value: Int, compact: Boolean = true) : this(BigInteger.valueOf(value.toLong()), compact = compact)
@JvmOverloads constructor(value: Float, compact: Boolean = true) : this(BigDecimal(value.toString()), compact = compact)
@JvmOverloads constructor(value: Double, compact: Boolean = true) : this(BigDecimal(value.toString()), compact = compact)
@JvmOverloads constructor(value: String, compact: Boolean = true) : this(BigDecimal(value), compact = compact)
@JvmOverloads constructor(value: Long, div: Long, compact: Boolean = true) : this(BigInteger.valueOf(value), BigInteger.valueOf(div), compact = compact)
@JvmOverloads constructor(value: Int, div: Int, compact: Boolean = true) : this(BigInteger.valueOf(value.toLong()), BigInteger.valueOf(div.toLong()), compact = compact)
@JvmOverloads constructor(value: Float, div: Float, compact: Boolean = true) : this(BigDecimal(value.toString()), BigDecimal(div.toString()), compact = compact)
@JvmOverloads constructor(value: Double, div: Double, compact: Boolean = true) : this(BigDecimal(value.toString()), BigDecimal(div.toString()), compact = compact)
@JvmOverloads constructor(value: String, div: String, compact: Boolean = true) : this(BigDecimal(value), BigDecimal(div), compact = compact)
@JvmOverloads constructor(value: BigDecimal, compact: Boolean = true) : this(powUnscaled(value.unscaledValue(), value.scale()), powScale(value.scale()), compact = compact)
@JvmOverloads constructor(value: BigDecimal, div: BigDecimal, compact: Boolean = true) : this(powUnscaled(value.unscaledValue(), value.scale()).multiply(powScale(div.scale())), powScale(value.scale()).multiply(powUnscaled(div.unscaledValue(), div.scale())), compact = compact)
override fun equals(other: Any?): Boolean {
if (other is Fraction) {
if (other.divisor == divisor)
return other.value == value
val a = value * other.divisor
val b = other.value * divisor
return a == b
}
return false
}
override fun hashCode(): Int {
return 31 * value.hashCode() + divisor.hashCode()
}
fun compactAndCanonize(): Fraction {
if (value == BigInteger.ZERO || value == BigInteger.ONE || divisor == BigInteger.ONE)
return this
val a = signnum()
val b = value.signum()
val c = divisor.signum()
if (a != b && a != c) {
if (isZero(divisor))
return Fraction(-value, -divisor)
val mod = value.divideAndRemainder(divisor)
if (isZero(mod[1]))
return Fraction(mod[0], compact = compact)
return Fraction(-value, -divisor)
}
if (isZero(divisor))
return this
return compactTwo(value, divisor, compact)
}
fun isZero(): Boolean {
if (isNaN()) return false
return value == BigInteger.ZERO
}
fun isOne(): Boolean {
if (isNaN()) return false
return value != BigInteger.ZERO && value == divisor
}
fun compact(): Fraction {
if (isNaN()) return this
if (value == BigInteger.ZERO || value == BigInteger.ONE || divisor == BigInteger.ONE)
return this
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return this
return compactTwo(value, divisor, compact)
}
fun canonize(): Fraction {
if (isNaN()) return this
if (value == BigInteger.ZERO || value == BigInteger.ONE || divisor == BigInteger.ONE || divisor == BigInteger.ZERO)
return this
val a = signnum()
val b = value.signum()
val c = divisor.signum()
if (a != b && a != c)
return Fraction(-value, -divisor)
return this
}
// Операторы
fun equalsCompact(other: Fraction?): Boolean {
if (other == null)
return false
if (isNaN() || other.isNaN()) return false
val a = compact()
val b = other.compact()
return a.value == b.value && a.divisor == b.divisor
}
override operator fun compareTo(other: Fraction): Int {
if (isNaN() || other.isNaN()) return 0
if (divisor == other.divisor)
return value.compareTo(other.value)
val a = signnum()
val b = other.signnum()
if (a == b && a == 0)
return 0
if (a < b)
return -1
else if (a > b)
return 1
val cmp = (value * other.divisor).compareTo(other.value * divisor)
if (a != value.signum() && a != divisor.signum()) {
if (b != other.value.signum() && b != other.divisor.signum()) {
return cmp
}
return invertCompare(cmp)
} else if (b != other.value.signum() && b != other.divisor.signum()) {
return invertCompare(cmp)
}
return cmp
}
private fun plusCompact(other: Fraction): Fraction {
if (isNaN()) return this
if (divisor == other.divisor) {
if (isOne(divisor))
return Fraction(value + other.value, divisor)
val new = value + other.value
if (new.compareTo(BigInteger.ZERO) == 0)
return ZERO
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return Fraction(new, divisor)
return compactTwo(new, divisor)
}
val new = value * other.divisor + other.value * divisor
val div = divisor * other.divisor
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun plus(other: Fraction): Fraction {
if (isNaN()) return this
if (other.isNaN()) return other
if (compact)
return plusCompact(other)
if (divisor == other.divisor) {
return Fraction(value + other.value, divisor, compact = false)
}
return Fraction(value * other.divisor + other.value * divisor, divisor * other.divisor, compact = false)
}
private fun minusCompact(other: Fraction): Fraction {
if (divisor == other.divisor) {
if (isOne(divisor))
return Fraction(value - other.value, divisor)
val new = value - other.value
if (new.compareTo(BigInteger.ZERO) == 0)
return ZERO
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return Fraction(new, divisor)
return compactTwo(new, divisor)
}
val new = value * other.divisor - other.value * divisor
val div = divisor * other.divisor
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun minus(other: Fraction): Fraction {
if (isNaN()) return this
if (other.isNaN()) return other
if (compact)
return minusCompact(other)
if (divisor == other.divisor) {
return Fraction(value - other.value, divisor, compact = false)
}
return Fraction(value * other.divisor - other.value * divisor, divisor * other.divisor, compact = false)
}
private fun timesCompact(other: Fraction): Fraction {
val new = value * other.value
if (new.compareTo(BigInteger.ZERO) == 0)
return ZERO
val div = divisor * other.divisor
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun times(other: Fraction): Fraction {
if (isNaN()) return this
if (other.isNaN()) return other
if (other.isOne()) return this
if (compact)
return timesCompact(other)
return Fraction(value * other.value, divisor * other.divisor, compact = false)
}
private fun divCompact(other: Fraction): Fraction {
val new = value * other.divisor
if (new.compareTo(BigInteger.ZERO) == 0)
return ZERO
val div = divisor * other.value
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun div(other: Fraction): Fraction {
if (isNaN()) return this
if (other.isNaN()) return other
if (other.isOne()) return this
if (compact)
return divCompact(other)
return Fraction(value * other.divisor, divisor * other.value, compact = false)
}
operator fun unaryMinus(): Fraction {
if (isNaN()) return this
return Fraction(-value, divisor)
}
operator fun unaryPlus(): Fraction {
return this
}
operator fun plus(other: Float): Fraction = plus(Fraction(other))
operator fun minus(other: Float): Fraction = minus(Fraction(other))
operator fun times(other: Float): Fraction = times(Fraction(other))
operator fun div(other: Float): Fraction = div(Fraction(other))
operator fun plus(other: Double): Fraction = plus(Fraction(other))
operator fun minus(other: Double): Fraction = minus(Fraction(other))
operator fun times(other: Double): Fraction = times(Fraction(other))
operator fun div(other: Double): Fraction = div(Fraction(other))
// может вызвать путаницу
/*
operator fun plus(other: BigDecimal): Fraction = plus(Fraction(other))
operator fun minus(other: BigDecimal): Fraction = minus(Fraction(other))
operator fun times(other: BigDecimal): Fraction = times(Fraction(other))
operator fun div(other: BigDecimal): Fraction = div(Fraction(other))
operator fun plus(other: BigInteger): Fraction = plus(Fraction(other))
operator fun minus(other: BigInteger): Fraction = minus(Fraction(other))
operator fun times(other: BigInteger): Fraction = times(Fraction(other))
operator fun div(other: BigInteger): Fraction = div(Fraction(other))
*/
operator fun plus(other: Int): Fraction = plus(Fraction(other))
operator fun minus(other: Int): Fraction = minus(Fraction(other))
operator fun times(other: Int): Fraction = times(Fraction(other))
operator fun div(other: Int): Fraction = div(Fraction(other))
operator fun plus(other: Long): Fraction = plus(Fraction(other))
operator fun minus(other: Long): Fraction = minus(Fraction(other))
operator fun times(other: Long): Fraction = times(Fraction(other))
operator fun div(other: Long): Fraction = div(Fraction(other))
/*
fun add(other: Float): Fraction = plus(Fraction(other))
fun subtract(other: Float): Fraction = minus(Fraction(other))
fun multiply(other: Float): Fraction = times(Fraction(other))
fun divide(other: Float): Fraction = div(Fraction(other))
fun add(other: Double): Fraction = plus(Fraction(other))
fun subtract(other: Double): Fraction = minus(Fraction(other))
fun multiply(other: Double): Fraction = times(Fraction(other))
fun divide(other: Double): Fraction = div(Fraction(other))
fun add(other: Int): Fraction = plus(Fraction(other))
fun subtract(other: Int): Fraction = minus(Fraction(other))
fun multiply(other: Int): Fraction = times(Fraction(other))
fun divide(other: Int): Fraction = div(Fraction(other))
fun add(other: Long): Fraction = plus(Fraction(other))
fun subtract(other: Long): Fraction = minus(Fraction(other))
fun multiply(other: Long): Fraction = times(Fraction(other))
fun divide(other: Long): Fraction = div(Fraction(other))
fun add(other: Fraction): Fraction = plus(other)
fun subtract(other: Fraction): Fraction = minus(other)
fun multiply(other: Fraction): Fraction = times(other)
fun divide(other: Fraction): Fraction = div(other)
*/
operator fun rem(other: Fraction): Fraction {
if (isNaN()) return this
if (other.isNaN()) return other
return Fraction((this / other).wholePart())
}
// Преобразования
override fun toFloat(): Float {
if (isNaN()) return Float.NaN
return (value / divisor).toFloat() + ((value % divisor).toFloat() / divisor.toFloat())
}
override fun toDouble(): Double {
if (isNaN()) return Double.NaN
return (value / divisor).toDouble() + ((value % divisor).toDouble() / divisor.toDouble())
}
fun toImpreciseFraction(): Decimal {
if (isNaN())
return Decimal.NaN
val div = value.divideAndRemainder(divisor)
val a = divisor.toDouble()
val b = div[1].toDouble()
if (b == 0.0 || !a.isFinite() || !b.isFinite()) {
return Decimal(div[0])
}
val div2 = a / b
if (div2.isFinite() && !div2.isNaN()) {
return Decimal(div[0], div2)
}
return Decimal(div[0])
}
fun toByteArray(): ByteArray {
if (isNaN()) {
return byteArrayOf(1, 0, 0, 0, 0, 1, 0, 0, 0, 0)
}
val magValue = magnitude(value)
val magDiv = magnitude(divisor)
val bytesA = magValue.value.toByteArray()
val bytesB = magDiv.value.toByteArray()
return byteArrayOf(
(bytesA.size and 0xFF).toByte(),
(bytesA.size ushr 8).toByte(),
(magValue.mag and 0xFF).toByte(),
(magValue.mag ushr 8).toByte(),
*bytesA,
(bytesB.size and 0xFF).toByte(),
(bytesB.size ushr 8).toByte(),
(magDiv.mag and 0xFF).toByte(),
(magDiv.mag ushr 8).toByte(),
*bytesB
)
}
override fun toInt(): Int {
if (isNaN()) throw ArithmeticException("Fraction is not a number")
return (value / divisor).toInt()
}
override fun toLong(): Long {
if (isNaN()) throw ArithmeticException("Fraction is not a number")
return (value / divisor).toLong()
}
override fun toByte(): Byte {
return toInt().toByte()
}
override fun toChar(): Char {
return toInt().toChar()
}
override fun toShort(): Short {
return toInt().toShort()
}
@JvmOverloads
fun toBigDecimal(context: MathContext = DEFAULT_MATH_CONTEXT): BigDecimal {
if (isNaN()) throw ArithmeticException("Fraction is not a number")
return BigDecimal(value).divide(BigDecimal(divisor), context)
}
// Утилиты
fun wholePart(): BigInteger {
if (isNaN()) throw ArithmeticException("Fraction is not a number")
return value / divisor
}
fun fractionPart(): Fraction {
if (isNaN()) return this
return Fraction(value % divisor, divisor)
}
fun modPart(): BigInteger {
if (isNaN()) throw ArithmeticException("Fraction is not a number")
return value % divisor
}
override fun toString(): String {
if (isNaN()) return "NaN"
return "$value/$divisor"
}
fun formattedString(): String {
if (isNaN()) return "NaN"
return "${wholePart()} ${modPart()}/$divisor"
}
@JvmOverloads
fun decimalString(nums: Int = 2, strict: Boolean = false): String {
if (isNaN()) return "NaN"
val whole = wholePart()
val fraction = modPart()
if (fraction == BigInteger.ZERO) {
if (!strict)
return whole.toString()
return "${whole}.${"0".repeat(nums)}"
}
var strdec = (fraction.toDouble() / divisor.toDouble()).toString()
if (strdec.length == 1) {
strdec = ""
if (strict) {
strdec = "0".repeat(nums)
}
} else {
strdec = strdec.substring(2)
if (strict && strdec.length < nums) {
strdec += "0".repeat(nums - strdec.length)
} else if (strdec.length > nums) {
strdec = strdec.substring(0, nums)
}
}
if (strdec == "") {
return whole.toString()
}
return "${whole}.$strdec"
}
fun signnum(): Int {
if (isNaN()) return 0
val a = value.signum()
val b = divisor.signum()
if (a == b) {
if (a == 0)
return 0
return 1
}
return -1
}
fun serializeNBT(): ByteArrayTag {
return ByteArrayTag(toByteArray())
}
fun isNaN(): Boolean {
return divisor == BigInteger.ZERO
}
fun write(buff: FriendlyByteBuf) {
buff.writeByteArray(toByteArray())
}
fun max(vararg others: Fraction): Fraction {
var max = this
for (other in others) {
if (max < other) {
max = other
}
}
return max
}
fun min(vararg others: Fraction): Fraction {
var min = this
for (other in others) {
if (min > other) {
min = other
}
}
return min
}
fun moreThanZero(): Fraction {
if (signnum() >= 0)
return this
return ZERO
}
fun lessOrZero(): Fraction {
if (signnum() <= 0)
return this
return ZERO
}
// Позволяет получить процент от деления данного на divisor с точностью до 5 цифр
fun percentage(divisor: Fraction, zeroing: Boolean = true): Float {
if (divisor.isZero() && zeroing) return 0f
if (isNaN() || divisor.isNaN()) return Float.NaN
val mul = (this * TEN_THOUSAND) / divisor
if (mul.isNaN()) return Float.NaN
return mul.wholePart().toFloat() / 10_000f
}
companion object {
private val LOGGER = LogManager.getLogger()
@JvmField
val ZERO = Fraction(BigInteger.ZERO)
@JvmField
val NaN = Fraction(BigInteger.ZERO, BigInteger.ZERO)
@JvmField
val ONE_HUNDRED = Fraction(BigInteger.valueOf(100))
@JvmField
val TEN_THOUSAND = Fraction(BigInteger.valueOf(10_000))
@JvmField
val HALF = Fraction(BigInteger.ONE, BigInteger.TWO)
@JvmField
val THIRD = Fraction(BigInteger.ONE, BigInteger.valueOf(3))
@JvmField
val ONE = Fraction(BigInteger.ONE)
@JvmField
val TWO = Fraction(BigInteger.TWO)
@JvmField
val MINUS_ONE = Fraction(-1)
@JvmField
val TEN = Fraction(BigInteger.TEN)
@JvmField
val INT_MAX_VALUE = Fraction(Int.MAX_VALUE)
@JvmField
val LONG_MAX_VALUE = Fraction(Long.MAX_VALUE)
@JvmStatic
fun read(buff: FriendlyByteBuf): Fraction {
return fromByteArray(buff.readByteArray())
}
@JvmStatic
fun fromByteArray(bytes: ByteArray): Fraction {
try {
val rangeA = unsignedInt(bytes[0]) or (unsignedInt(bytes[1]) shl 8)
val magA = unsignedInt(bytes[2]) or (unsignedInt(bytes[3]) shl 8)
val bytesA = bytes.copyOfRange(4, 4 + rangeA)
val offsetB = 4 + rangeA
val rangeB = unsignedInt(bytes[offsetB]) or (unsignedInt(bytes[offsetB + 1]) shl 8)
val magB = unsignedInt(bytes[offsetB + 2]) or (unsignedInt(bytes[offsetB + 3]) shl 8)
val bytesB = bytes.copyOfRange(offsetB + 4, offsetB + 4 + rangeB)
if (bytesB.isEmpty())
return NaN
return Fraction(if (bytesA.isNotEmpty()) (BigInteger(bytesA) * BigInteger("1" + "0".repeat(magA))) else BigInteger.ZERO, BigInteger(bytesB) * BigInteger("1" + "0".repeat(magB)))
} catch(err: Throwable) {
LOGGER.error("Unable to load Fraction from byte array", err)
return NaN
}
}
@JvmStatic
fun deserializeNBT(bytesTag: ByteArrayTag): Fraction {
val bytes = bytesTag.asByteArray
return fromByteArray(bytes)
}
// Преобразование строки в дробь с подавлением ошибок форматирования
@JvmStatic
fun fromString(str: String): Fraction {
try {
return Fraction(BigDecimal(str))
} catch(err: Throwable) {
return ZERO
}
}
@JvmStatic
fun deserializeNBT(tag: Tag?): Fraction {
if (tag == null)
return ZERO
if (tag is ByteArrayTag)
return deserializeNBT(tag)
if (tag is StringTag)
return try {
fromString(tag.asString)
} catch (anything: Throwable) {
ZERO
}
return ZERO
}
}
}

View File

@ -1,345 +0,0 @@
package ru.dbotthepony.mc.otm.tests
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Decimal
import java.math.BigDecimal
import java.math.BigInteger
object FractionTests {
@Test
@DisplayName("Fraction declaration")
fun declaration() {
println("BigInteger 1/1 == ${Fraction(BigInteger.valueOf(1), BigInteger.valueOf(1))}")
println("BigDecimal 1 == ${Fraction(BigDecimal("1"))}")
var one = BigDecimal("1.00")
println("Unscaled ${one.unscaledValue()} with scale ${one.scale()} of $one")
println("BigDecimal $one == ${Fraction(one)}")
assert(Fraction(one).compareTo(Fraction.ONE) == 0)
one = BigDecimal("1.0000")
println("Unscaled ${one.unscaledValue()} with scale ${one.scale()} of $one")
println("BigDecimal $one == ${Fraction(one)}")
assert(Fraction(one).compareTo(Fraction.ONE) == 0)
println("1/2 == ${Fraction(1, 2)}")
println("-1/2 == ${Fraction(-1, 2)}")
println("1/-2 == ${Fraction(1, -2)}")
println("-1/-2 == ${Fraction(-1, -2)}")
println("canonical 1/2 == ${Fraction(1, 2).canonize()}")
println("canonical -1/2 == ${Fraction(-1, 2).canonize()}")
println("canonical 1/-2 == ${Fraction(1, -2).canonize()}")
println("canonical -1/-2 == ${Fraction(-1, -2).canonize()}")
}
@Test
@DisplayName("Fraction NaN behavior")
fun nan() {
assert((Fraction.NaN + Fraction.ONE).isNaN())
assert((Fraction.NaN - Fraction.ONE).isNaN())
assert((Fraction.NaN / Fraction.ONE).isNaN())
assert((Fraction.NaN * Fraction.ONE).isNaN())
assert((Fraction.ONE + Fraction.NaN).isNaN())
assert((Fraction.ONE - Fraction.NaN).isNaN())
assert((Fraction.ONE / Fraction.NaN).isNaN())
assert((Fraction.ONE * Fraction.NaN).isNaN())
assert((Fraction.ONE / Fraction.ZERO).isNaN())
assert((Fraction.ONE * Fraction(0, 0)).isNaN())
assert((Fraction.ONE * Fraction(1, 0)).isNaN())
assert(Fraction.NaN.toFloat().isNaN())
assert(Fraction.NaN.toDouble().isNaN())
assertThrows<ArithmeticException> {Fraction.NaN.toInt()}
assertThrows<ArithmeticException> {Fraction.NaN.toLong()}
assertThrows<ArithmeticException> {Fraction.NaN.wholePart()}
assert(Fraction.fromByteArray(Fraction.NaN.toByteArray()).isNaN())
assert(Fraction.NaN.percentage(Fraction.ONE).isNaN())
}
@Test
@DisplayName("Fraction comparison")
fun equality() {
assert(Fraction(1).compareTo(Fraction.ONE) == 0)
assert(Fraction(1.0).compareTo(Fraction.ONE) == 0)
assert(Fraction(1.0F).compareTo(Fraction.ONE) == 0)
assert(Fraction(1, 1).compareTo(Fraction.ONE) == 0)
assert(Fraction(1.0, 1.0).compareTo(Fraction.ONE) == 0)
assert(Fraction(1.0F, 1.0F).compareTo(Fraction.ONE) == 0)
assert(Fraction(1, 2).compareTo(Fraction.HALF) == 0)
assert(Fraction(1.0, 2.0).compareTo(Fraction.HALF) == 0)
assert(Fraction(1.0F, 2.0F).compareTo(Fraction.HALF) == 0)
assert(Fraction(-1, -2).compareTo(Fraction.HALF) == 0)
assert(Fraction(-1.0, -2.0).compareTo(Fraction.HALF) == 0)
assert(Fraction(-1.0F, -2.0F).compareTo(Fraction.HALF) == 0)
assert(Fraction(-1, 2).compareTo(Fraction.HALF) != 0)
assert(Fraction(-1.0, 2.0).compareTo(Fraction.HALF) != 0)
assert(Fraction(-1.0F, 2.0F).compareTo(Fraction.HALF) != 0)
assert(Fraction(1, 2).compareTo(Fraction.ONE) != 0)
assert(Fraction(1.0, 2.0).compareTo(Fraction.ONE) != 0)
assert(Fraction(1.0F, 2.0F).compareTo(Fraction.ONE) != 0)
assert(Fraction(2).compareTo(Fraction.TWO) == 0)
assert(Fraction(2.0).compareTo(Fraction.TWO) == 0)
assert(Fraction(2.0F).compareTo(Fraction.TWO) == 0)
assert(Fraction(2, 1).compareTo(Fraction.TWO) == 0)
assert(Fraction(2.0, 1.0).compareTo(Fraction.TWO) == 0)
assert(Fraction(2.0F, 1.0F).compareTo(Fraction.TWO) == 0)
assert(Fraction(4, 3) > Fraction(5, 4))
assert(Fraction(4, 4) < Fraction(5, 4))
assert(Fraction(-15, 2) < Fraction(2, 4))
assert(Fraction(-1, 2) < Fraction(2, 4))
assert(Fraction(-15, -2) > Fraction(2, 4))
assert(Fraction(-15, -2) > Fraction(-2, -4))
assert(Fraction(-15, 2) < Fraction(-2, -4))
}
@Test
@DisplayName("Fraction math")
fun math() {
assert((Fraction(1) / Fraction(1)) == Fraction(1))
assert((Fraction(2) / Fraction(1)) == Fraction(2, 1))
assert((Fraction(2) / Fraction(2)) == Fraction(1)) { Fraction(2) / Fraction(2) }
assert((Fraction(4, 3) / Fraction(5, 4)) == (Fraction(4, 3) * Fraction(4, 5)))
assert((Fraction(4, 3) + Fraction(5, 4)) == Fraction(31, 12))
}
@Test
@DisplayName("Fraction compacting")
fun compacting() {
val frac = Fraction("2721280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "25600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
println("Compacting $frac => ${frac + Fraction.ZERO}")
}
private val samples = arrayOf(
Fraction(9475, 4729),
Fraction(23535, 58723),
Fraction(-4852, 6859),
Fraction(-45623, -76849),
Fraction(38494, -76849),
Fraction(1043, -648),
)
private val samplesIM = arrayOf(
Decimal(9475.0 / 4729),
Decimal(23535.0 / 58723),
Decimal(-4852.0 / 6859),
Decimal(-45623.0 / -76849),
Decimal(38494.0 / -76849),
Decimal(1043.0 / -648),
)
private val samples2 = arrayOf(
(9475.0 / 4729),
(23535.0 / 58723),
(-4852.0 / 6859),
(-45623.0 / -76849),
(38494.0 / -76849),
(1043.0 / -648),
)
private val samples3 = arrayOf(
BigDecimal((9475.0 / 4729).toString()),
BigDecimal((23535.0 / 58723).toString()),
BigDecimal((-4852.0 / 6859).toString()),
BigDecimal((-45623.0 / -76849).toString()),
BigDecimal((38494.0 / -76849).toString()),
BigDecimal((1043.0 / -648).toString()),
)
@Test
@DisplayName("Fraction performance measurement")
fun performance() {
val rand = java.util.Random()
val blackHole = arrayOfNulls<Fraction>(100_000)
val blackHoleIM = arrayOfNulls<Decimal>(100_000)
val size = samples.size
var time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHole[i] = samples[rand.nextInt(size)] + samples[rand.nextInt(size)]
1 -> blackHole[i] = samples[rand.nextInt(size)] - samples[rand.nextInt(size)]
2 -> blackHole[i] = samples[rand.nextInt(size)] * samples[rand.nextInt(size)]
// 3 -> blackHole[i] = samples[rand.nextInt(size)] / samples[rand.nextInt(size)]
}
}
println("Mean time for Fraction operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHoleIM[i] = samplesIM[rand.nextInt(size)] + samplesIM[rand.nextInt(size)]
1 -> blackHoleIM[i] = samplesIM[rand.nextInt(size)] - samplesIM[rand.nextInt(size)]
2 -> blackHoleIM[i] = samplesIM[rand.nextInt(size)] * samplesIM[rand.nextInt(size)]
// 3 -> blackHole[i] = samples[rand.nextInt(size)] / samples[rand.nextInt(size)]
}
}
println("Mean time for ImpreciseFraction operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
var sum = Fraction.ZERO
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum += blackHole[i]!!
blackHole[i] = blackHole[rand.nextInt(size)]
}
val blackHole2 = DoubleArray(100_000)
time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHole2[i] = samples2[rand.nextInt(size)] + samples2[rand.nextInt(size)]
1 -> blackHole2[i] = samples2[rand.nextInt(size)] - samples2[rand.nextInt(size)]
2 -> blackHole2[i] = samples2[rand.nextInt(size)] * samples2[rand.nextInt(size)]
// 3 -> blackHole2[i] = samples2[rand.nextInt(size)] / samples2[rand.nextInt(size)]
}
}
println("Mean time for Double operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
val blackHole3 = arrayOfNulls<BigDecimal>(100_000)
time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHole3[i] = samples3[rand.nextInt(size)] + samples3[rand.nextInt(size)]
1 -> blackHole3[i] = samples3[rand.nextInt(size)] - samples3[rand.nextInt(size)]
2 -> blackHole3[i] = samples3[rand.nextInt(size)] * samples3[rand.nextInt(size)]
// 3 -> blackHole2[i] = samples2[rand.nextInt(size)] / samples2[rand.nextInt(size)]
}
}
println("Mean time for BigDecimal operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
var sum2 = 0.0
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum2 += blackHole2[i]
blackHole2[i] = blackHole2[rand.nextInt(size)]
}
var sum3 = 0.0
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum3 += blackHole2[i]
blackHole3[i] = blackHole3[rand.nextInt(size)]
}
var sum4 = 0.0
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum4 += blackHoleIM[i]!!.toDouble()
blackHoleIM[i] = blackHoleIM[rand.nextInt(size)]
}
println("$sum $sum2 $sum3")
}
@Test
@DisplayName("Fraction serialization test")
fun serialization() {
var value = Fraction(1)
var serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction(4, 2)
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction(-4, 2)
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction(-4, -18)
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("3407203485237459085739045724837543569234750927348902374590872345", "-57777772398450982374590230984532984")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("320", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("324", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("328", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("332", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("336", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
}
@Test
@DisplayName("Fraction inaccurate representation")
fun inaccurate() {
var value = 1.1
var frac = Fraction(value)
assert(frac.toDouble() == value) { "$value != $frac as (${frac.toDouble()})" }
value = 1.45
frac = Fraction(value)
assert(frac.toDouble() == value) { "$value != $frac as (${frac.toDouble()})" }
value = -1.0
frac = Fraction(value)
assert(frac.toDouble() == value) { "$value != $frac as (${frac.toDouble()})" }
value = -254.66
frac = Fraction(value)
assert(frac.toDouble() == value) { "$value != $frac as (${frac.toDouble()})" }
value = 94.949494
frac = Fraction(value)
assert(frac.toDouble() == value) { "$value != $frac as (${frac.toDouble()})" }
value = 1.0 / 3
frac = Fraction(value)
assert(frac.toDouble() == value) { "$value != $frac as (${frac.toDouble()})" }
}
}