Remove Fraction class
This commit is contained in:
parent
5149b7432d
commit
ce437d4e14
@ -729,18 +729,6 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0
|
|||||||
return toInt().toShort()
|
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 {
|
fun percentage(divisor: Decimal, zeroing: Boolean = true): Float {
|
||||||
if ((isZero || divisor.isZero) && zeroing) return 0f
|
if ((isZero || divisor.isZero) && zeroing) return 0f
|
||||||
if (isNaN || divisor.isNaN || divisor.isZero) return Float.NaN
|
if (isNaN || divisor.isNaN || divisor.isZero) return Float.NaN
|
||||||
|
@ -59,19 +59,6 @@ fun Number.dynPlus(other: Number): Number {
|
|||||||
is Int, is Byte, is Short -> this + other.toInt()
|
is Int, is Byte, is Short -> this + other.toInt()
|
||||||
is Long -> this + other.toLong()
|
is Long -> this + other.toLong()
|
||||||
is Decimal -> this + other
|
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)")
|
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 Int, is Byte, is Short -> this - other.toInt()
|
||||||
is Long -> this - other.toLong()
|
is Long -> this - other.toLong()
|
||||||
is Decimal -> this - other
|
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)")
|
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 Int, is Byte, is Short -> this * other.toInt()
|
||||||
is Long -> this * other.toLong()
|
is Long -> this * other.toLong()
|
||||||
is Decimal -> this * other
|
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)")
|
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 Int, is Byte, is Short -> this / other.toInt()
|
||||||
is Long -> this / other.toLong()
|
is Long -> this / other.toLong()
|
||||||
is Decimal -> this / other
|
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)")
|
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
|
val Number.isWhole get() = !isFractional
|
||||||
|
|
||||||
fun Number.toDecimal(): Decimal {
|
fun Number.toDecimal(): Decimal {
|
||||||
@ -218,7 +166,6 @@ fun Number.toDecimal(): Decimal {
|
|||||||
is Byte -> Decimal(this)
|
is Byte -> Decimal(this)
|
||||||
is Short -> Decimal(this)
|
is Short -> Decimal(this)
|
||||||
is Long -> Decimal(this)
|
is Long -> Decimal(this)
|
||||||
is Fraction -> this.toImpreciseFraction()
|
|
||||||
else -> throw ClassCastException("Can not turn $this into ImpreciseFraction")
|
else -> throw ClassCastException("Can not turn $this into ImpreciseFraction")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,6 @@ enum class SiPrefix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val decimal = BigDecimal(string)
|
val decimal = BigDecimal(string)
|
||||||
val fraction = Fraction(decimal)
|
|
||||||
val impreciseFraction = Decimal(string)
|
val impreciseFraction = Decimal(string)
|
||||||
val integer = if (!fractional) BigInteger(string) else null
|
val integer = if (!fractional) BigInteger(string) else null
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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()})" }
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user