/* * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ // Copyright 2009 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. package kotlin internal fun Long.toNumber() = high * TWO_PWR_32_DBL_ + getLowBitsUnsigned() internal fun Long.getLowBitsUnsigned() = if (low >= 0) low.toDouble() else TWO_PWR_32_DBL_ + low internal fun hashCode(l: Long) = l.low xor l.high internal fun Long.toStringImpl(radix: Int): String { if (radix < 2 || 36 < radix) { throw Exception("radix out of range: $radix") } if (isZero()) { return "0" } if (isNegative()) { if (equalsLong(MIN_VALUE)) { // We need to change the Long value before it can be negated, so we remove // the bottom-most digit in this base and then recurse to do the rest. val radixLong = fromInt(radix) val div = div(radixLong) val rem = div.multiply(radixLong).subtract(this).toInt() // Using rem.asDynamic() to break dependency on "kotlin.text" package return div.toStringImpl(radix) + rem.asDynamic().toString(radix).unsafeCast() } else { return "-${negate().toStringImpl(radix)}" } } // Do several digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. val digitsPerTime = when { radix == 2 -> 31 radix <= 10 -> 9 radix <= 21 -> 7 radix <= 35 -> 6 else -> 5 } val radixToPower = fromNumber(JsMath.pow(radix.toDouble(), digitsPerTime.toDouble())) var rem = this var result = "" while (true) { val remDiv = rem.div(radixToPower) val intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() var digits = intval.asDynamic().toString(radix).unsafeCast() rem = remDiv if (rem.isZero()) { return digits + result } else { while (digits.length < digitsPerTime) { digits = "0" + digits } result = digits + result } } } internal fun Long.negate() = unaryMinus() internal fun Long.isZero() = high == 0 && low == 0 internal fun Long.isNegative() = high < 0 internal fun Long.isOdd() = low and 1 == 1 internal fun Long.equalsLong(other: Long) = high == other.high && low == other.low internal fun Long.lessThan(other: Long) = compare(other) < 0 internal fun Long.lessThanOrEqual(other: Long) = compare(other) <= 0 internal fun Long.greaterThan(other: Long) = compare(other) > 0 internal fun Long.greaterThanOrEqual(other: Long) = compare(other) >= 0 internal fun Long.compare(other: Long): Int { if (equalsLong(other)) { return 0; } val thisNeg = isNegative(); val otherNeg = other.isNegative(); return when { thisNeg && !otherNeg -> -1 !thisNeg && otherNeg -> 1 // at this point, the signs are the same, so subtraction will not overflow subtract(other).isNegative() -> -1 else -> 1 } } internal fun Long.add(other: Long): Long { // Divide each number into 4 chunks of 16 bits, and then sum the chunks. val a48 = high ushr 16 val a32 = high and 0xFFFF val a16 = low ushr 16 val a00 = low and 0xFFFF val b48 = other.high ushr 16 val b32 = other.high and 0xFFFF val b16 = other.low ushr 16 val b00 = other.low and 0xFFFF var c48 = 0 var c32 = 0 var c16 = 0 var c00 = 0 c00 += a00 + b00 c16 += c00 ushr 16 c00 = c00 and 0xFFFF c16 += a16 + b16 c32 += c16 ushr 16 c16 = c16 and 0xFFFF c32 += a32 + b32 c48 += c32 ushr 16 c32 = c32 and 0xFFFF c48 += a48 + b48 c48 = c48 and 0xFFFF return Long((c16 shl 16) or c00, (c48 shl 16) or c32) } internal fun Long.subtract(other: Long) = add(other.unaryMinus()) internal fun Long.multiply(other: Long): Long { if (isZero()) { return ZERO } else if (other.isZero()) { return ZERO } if (equalsLong(MIN_VALUE)) { return if (other.isOdd()) MIN_VALUE else ZERO } else if (other.equalsLong(MIN_VALUE)) { return if (isOdd()) MIN_VALUE else ZERO } if (isNegative()) { return if (other.isNegative()) { negate().multiply(other.negate()) } else { negate().multiply(other).negate() } } else if (other.isNegative()) { return multiply(other.negate()).negate() } // If both longs are small, use float multiplication if (lessThan(TWO_PWR_24_) && other.lessThan(TWO_PWR_24_)) { return fromNumber(toNumber() * other.toNumber()) } // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. // We can skip products that would overflow. val a48 = high ushr 16 val a32 = high and 0xFFFF val a16 = low ushr 16 val a00 = low and 0xFFFF val b48 = other.high ushr 16 val b32 = other.high and 0xFFFF val b16 = other.low ushr 16 val b00 = other.low and 0xFFFF var c48 = 0 var c32 = 0 var c16 = 0 var c00 = 0 c00 += a00 * b00 c16 += c00 ushr 16 c00 = c00 and 0xFFFF c16 += a16 * b00 c32 += c16 ushr 16 c16 = c16 and 0xFFFF c16 += a00 * b16 c32 += c16 ushr 16 c16 = c16 and 0xFFFF c32 += a32 * b00 c48 += c32 ushr 16 c32 = c32 and 0xFFFF c32 += a16 * b16 c48 += c32 ushr 16 c32 = c32 and 0xFFFF c32 += a00 * b32 c48 += c32 ushr 16 c32 = c32 and 0xFFFF c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 c48 = c48 and 0xFFFF return Long(c16 shl 16 or c00, c48 shl 16 or c32) } internal fun Long.divide(other: Long): Long { if (other.isZero()) { throw Exception("division by zero") } else if (isZero()) { return ZERO } if (equalsLong(MIN_VALUE)) { if (other.equalsLong(ONE) || other.equalsLong(NEG_ONE)) { return MIN_VALUE // recall that -MIN_VALUE == MIN_VALUE } else if (other.equalsLong(MIN_VALUE)) { return ONE } else { // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. val halfThis = shiftRight(1) val approx = halfThis.div(other).shiftLeft(1) if (approx.equalsLong(ZERO)) { return if (other.isNegative()) ONE else NEG_ONE } else { val rem = subtract(other.multiply(approx)) return approx.add(rem.div(other)) } } } else if (other.equalsLong(MIN_VALUE)) { return ZERO } if (isNegative()) { return if (other.isNegative()) { negate().div(other.negate()) } else { negate().div(other).negate() } } else if (other.isNegative()) { return div(other.negate()).negate() } // Repeat the following until the remainder is less than other: find a // floating-point that approximates remainder / other *from below*, add this // into the result, and subtract it from the remainder. It is critical that // the approximate value is less than or equal to the real value so that the // remainder never becomes negative. var res = ZERO var rem = this while (rem.greaterThanOrEqual(other)) { // Approximate the result of division. This may be a little greater or // smaller than the actual value. val approxDouble = rem.toNumber() / other.toNumber() var approx2 = JsMath.max(1.0, JsMath.floor(approxDouble)) // We will tweak the approximate result by changing it in the 48-th digit or // the smallest non-fractional digit, whichever is larger. val log2 = JsMath.ceil(JsMath.log(approx2) / JsMath.LN2) val delta = if (log2 <= 48) 1.0 else JsMath.pow(2.0, log2 - 48) // Decrease the approximation until it is smaller than the remainder. Note // that if it is too large, the product overflows and is negative. var approxRes = fromNumber(approx2) var approxRem = approxRes.multiply(other) while (approxRem.isNegative() || approxRem.greaterThan(rem)) { approx2 -= delta approxRes = fromNumber(approx2) approxRem = approxRes.multiply(other) } // We know the answer can't be zero... and actually, zero would cause // infinite recursion since we would make no progress. if (approxRes.isZero()) { approxRes = ONE } res = res.add(approxRes) rem = rem.subtract(approxRem) } return res } internal fun Long.modulo(other: Long) = subtract(div(other).multiply(other)) internal fun Long.shiftLeft(numBits: Int): Long { @Suppress("NAME_SHADOWING") val numBits = numBits and 63 if (numBits == 0) { return this } else { if (numBits < 32) { return Long(low shl numBits, (high shl numBits) or (low ushr (32 - numBits))) } else { return Long(0, low shl (numBits - 32)) } } } internal fun Long.shiftRight(numBits: Int): Long { @Suppress("NAME_SHADOWING") val numBits = numBits and 63 if (numBits == 0) { return this } else { if (numBits < 32) { return Long((low ushr numBits) or (high shl (32 - numBits)), high shr numBits) } else { return Long(high shr (numBits - 32), if (high >= 0) 0 else -1) } } } internal fun Long.shiftRightUnsigned(numBits: Int): Long { @Suppress("NAME_SHADOWING") val numBits = numBits and 63 if (numBits == 0) { return this } else { if (numBits < 32) { return Long((low ushr numBits) or (high shl (32 - numBits)), high ushr numBits) } else return if (numBits == 32) { Long(high, 0) } else { Long(high ushr (numBits - 32), 0) } } } /** * Returns a Long representing the given (32-bit) integer value. * @param {number} value The 32-bit integer in question. * @return {!Kotlin.Long} The corresponding Long value. */ // TODO: cache internal fun fromInt(value: Int) = Long(value, if (value < 0) -1 else 0) /** * Converts this [Double] value to [Long]. * The fractional part, if any, is rounded down towards zero. * Returns zero if this `Double` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`, * [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`. */ internal fun fromNumber(value: Double): Long { if (value.isNaN()) { return ZERO; } else if (value <= -TWO_PWR_63_DBL_) { return MIN_VALUE; } else if (value + 1 >= TWO_PWR_63_DBL_) { return MAX_VALUE; } else if (value < 0) { return fromNumber(-value).negate(); } else { val twoPwr32 = TWO_PWR_32_DBL_ return Long( jsBitwiseOr(value.rem(twoPwr32), 0), jsBitwiseOr(value / twoPwr32, 0) ) } } private const val TWO_PWR_16_DBL_ = (1 shl 16).toDouble() private const val TWO_PWR_24_DBL_ = (1 shl 24).toDouble() //private val TWO_PWR_32_DBL_ = TWO_PWR_16_DBL_ * TWO_PWR_16_DBL_ private const val TWO_PWR_32_DBL_ = (1 shl 16).toDouble() * (1 shl 16).toDouble() //private val TWO_PWR_64_DBL_ = TWO_PWR_32_DBL_ * TWO_PWR_32_DBL_ private const val TWO_PWR_64_DBL_ = ((1 shl 16).toDouble() * (1 shl 16).toDouble()) * ((1 shl 16).toDouble() * (1 shl 16).toDouble()) //private val TWO_PWR_63_DBL_ = TWO_PWR_64_DBL_ / 2 private const val TWO_PWR_63_DBL_ = (((1 shl 16).toDouble() * (1 shl 16).toDouble()) * ((1 shl 16).toDouble() * (1 shl 16).toDouble())) / 2 private val ZERO = fromInt(0) private val ONE = fromInt(1) private val NEG_ONE = fromInt(-1) private val MAX_VALUE = Long(-1, -1 ushr 1) private val MIN_VALUE = Long(0, 1 shl 31) private val TWO_PWR_24_ = fromInt(1 shl 24)