@@ -179,3 +179,62 @@ internal fun multiplyAndAdd(d: Long, n: Long, r: Long): Long {
179179 }
180180 return safeAdd(safeMultiply(md, n), mr)
181181}
182+
183+ internal val POWERS_OF_TEN = intArrayOf(
184+ 1 ,
185+ 10 ,
186+ 100 ,
187+ 1000 ,
188+ 10000 ,
189+ 100000 ,
190+ 1000000 ,
191+ 10000000 ,
192+ 100000000 ,
193+ 1000000000
194+ )
195+
196+ /* *
197+ * The fraction [fractionalPart]/10^[digits].
198+ */
199+ internal class DecimalFraction (
200+ /* *
201+ * The numerator of the fraction.
202+ */
203+ val fractionalPart : Int ,
204+ /* *
205+ * The number of digits after the decimal point.
206+ */
207+ val digits : Int
208+ ): Comparable<DecimalFraction> {
209+ init {
210+ require(digits >= 0 ) { " Digits must be non-negative, but was $digits " }
211+ }
212+
213+ /* *
214+ * The integral numerator of the fraction, but with [newDigits] digits after the decimal point.
215+ * The rounding is done using the towards-zero rounding mode.
216+ */
217+ fun fractionalPartWithNDigits (newDigits : Int ): Int = when {
218+ newDigits == digits -> fractionalPart
219+ newDigits > digits -> fractionalPart * POWERS_OF_TEN [newDigits - digits]
220+ else -> fractionalPart / POWERS_OF_TEN [digits - newDigits]
221+ }
222+
223+ override fun compareTo (other : DecimalFraction ): Int =
224+ maxOf(digits, other.digits).let { maxPrecision ->
225+ fractionalPartWithNDigits(maxPrecision).compareTo(other.fractionalPartWithNDigits(maxPrecision))
226+ }
227+
228+ override fun equals (other : Any? ): Boolean = other is DecimalFraction && compareTo(other) == 0
229+
230+ override fun toString (): String = buildString {
231+ val denominator = POWERS_OF_TEN [digits]
232+ append(fractionalPart / denominator)
233+ append(' .' )
234+ append((denominator + (fractionalPart % denominator)).toString().removePrefix(" 1" ))
235+ }
236+
237+ override fun hashCode (): Int {
238+ throw UnsupportedOperationException (" DecimalFraction is not supposed to be used as a hash key" )
239+ }
240+ }
0 commit comments