java.math.BitLevel.scala Maven / Gradle / Ivy
/*
* Ported by Alistair Johnson from
* https://github.com/gwtproject/gwt/blob/master/user/super/com/google/gwt/emul/java/math/BitLevel.java
* Original license copied below:
*/
/*
* Copyright 2009 Google Inc.
*
* 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. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
*/
package java.math
/** Object that provides all the bit level operations for {@link BigInteger}.
*
* The operations are: - Left Shifting
* - Right Shifting
- Bit clearing
- Bit setting
- Bit
* counting
- Bit testing
- Getting of the lowest bit set
*
All operations are provided in immutable way, and some in both mutable
* and immutable.
*/
private[math] object BitLevel {
/** @see BigInteger#bitCount()
*
* @param bi
* @return
*/
def bitCount(bi: BigInteger): Int = {
var bCount = 0
if (bi.sign == 0) {
0
} else {
var i = bi.getFirstNonzeroDigit
if (bi.sign > 0) {
while (i < bi.numberLength) {
bCount += java.lang.Integer.bitCount(bi.digits(i))
i += 1
}
} else {
// (sign < 0) this digit absorbs the carry
bCount += java.lang.Integer.bitCount(-bi.digits(i))
i += 1
while (i < bi.numberLength) {
bCount += java.lang.Integer.bitCount(~bi.digits(i))
i += 1
}
// We take the complement sum:
bCount = (bi.numberLength << 5) - bCount
}
bCount
}
}
/** @see BigInteger#bitLength()
*
* @param bi
* @return
*/
def bitLength(bi: BigInteger): Int = {
if (bi.sign == 0) {
0
} else {
var bLength = bi.numberLength << 5
var highDigit = bi.digits(bi.numberLength - 1)
if (bi.sign < 0) {
val i = bi.getFirstNonzeroDigit
// We reduce the problem to the positive case.
if (i == bi.numberLength - 1)
highDigit -= 1
}
// Subtracting all sign bits
bLength -= java.lang.Integer.numberOfLeadingZeros(highDigit)
bLength
}
}
/** Performs a flipBit on the BigInteger.
*
* Returns a BigInteger with the specified bit flipped.
*
* @param bi BigInteger to operate on
* @param n the bit to flip
*/
def flipBit(bi: BigInteger, n: Int): BigInteger = {
val resSign = if (bi.sign == 0) 1 else bi.sign
val intCount = n >> 5
val bitN = n & 31
val resLength = Math.max(intCount + 1, bi.numberLength) + 1
val resDigits = new Array[Int](resLength)
var i: Int = 0
val bitNumber = 1 << bitN
System.arraycopy(bi.digits, 0, resDigits, 0, bi.numberLength)
if (bi.sign < 0) {
if (intCount >= bi.numberLength) {
resDigits(intCount) = bitNumber
} else {
val firstNonZeroDigit = bi.getFirstNonzeroDigit
if (intCount > firstNonZeroDigit) {
resDigits(intCount) ^= bitNumber
} else if (intCount < firstNonZeroDigit) {
resDigits(intCount) = -bitNumber
i = intCount + 1
while (i < firstNonZeroDigit) {
resDigits(i) = -1
i += 1
}
resDigits(i) -= 1
} else {
i = intCount
resDigits(i) = -((-resDigits(intCount)) ^ bitNumber)
if (resDigits(i) == 0) {
i += 1
while (resDigits(i) == -1) {
resDigits(i) = 0
i += 1
}
resDigits(i) += 1
}
}
}
} else {
// case where val is positive
resDigits(intCount) ^= bitNumber
}
val result = new BigInteger(resSign, resLength, resDigits)
result.cutOffLeadingZeroes()
result
}
/** Performs {@code val <<= count}. */
def inplaceShiftLeft(bi: BigInteger, count: Int): Unit = {
val intCount = count >> 5
val numZeros = Integer.numberOfLeadingZeros(bi.digits(bi.numberLength - 1))
val offset = if ((numZeros - (count & 31)) >= 0) 0 else 1
bi.numberLength += intCount + offset
shiftLeft(bi.digits, bi.digits, intCount, count & 31)
bi.cutOffLeadingZeroes()
bi.unCache()
}
/** Performs {@code val >>= count} where {@code val} is a positive number. */
def inplaceShiftRight(bi: BigInteger, count: Int): Unit = {
val sign = bi.signum()
if (!(count == 0 || bi.signum() == 0)) {
val intCount = count >> 5 // count of integers
bi.numberLength -= intCount
val shift =
shiftRight(bi.digits, bi.numberLength, bi.digits, intCount, count & 31)
if (!shift && sign < 0) {
// remainder not zero: add one to the result
var i = 0
while (i < bi.numberLength && (bi.digits(i) == -1)) {
bi.digits(i) = 0
i += 1
}
if (i == bi.numberLength)
bi.numberLength += 1
bi.digits(i) += 1
}
bi.cutOffLeadingZeroes()
bi.unCache()
}
}
/** Check if there are 1s in the lowest bits of this BigInteger.
*
* @param numberOfBits the number of the lowest bits to check
* @return false if all bits are 0s, true otherwise
*/
def nonZeroDroppedBits(numberOfBits: Int, digits: Array[Int]): Boolean = {
val intCount = numberOfBits >> 5
val bitCount = numberOfBits & 31
var i = 0
while (i < intCount && digits(i) == 0) {
i += 1
}
(i != intCount) || (digits(i) << (32 - bitCount) != 0)
}
/** @see BigInteger#shiftLeft(int).
*
* @param source
* @param count
* @return
*/
def shiftLeft(source: BigInteger, count: Int): BigInteger = {
val intCount: Int = count >> 5
val andCount: Int = count & 31
val offset = if (andCount == 0) 0 else 1
val resLength: Int = source.numberLength + intCount + offset
val resDigits = new Array[Int](resLength)
shiftLeft(resDigits, source.digits, intCount, andCount)
val result = new BigInteger(source.sign, resLength, resDigits)
result.cutOffLeadingZeroes()
result
}
/** Abstractly shifts left an array of integers in little endian.
*
* (i.e. shift it right). Total shift distance in bits is intCount * 32 + count
*
* @param result the destination array
* @param source the source array
* @param intCount the shift distance in integers
* @param count an additional shift distance in bits
*/
def shiftLeft(result: Array[Int],
source: Array[Int],
intCount: Int,
count: Int): Unit = {
if (count == 0) {
System.arraycopy(source, 0, result, intCount, result.length - intCount)
} else {
val rightShiftCount: Int = 32 - count
result(result.length - 1) = 0
var i = result.length - 1
while (i > intCount) {
result(i) |= (source(i - intCount - 1) >>> rightShiftCount)
result(i - 1) = (source(i - intCount - 1) << count)
i -= 1
}
}
for (i <- 0 until intCount) {
result(i) = 0
}
}
def shiftLeftOneBit(source: BigInteger): BigInteger = {
val srcLen = source.numberLength
val resLen = srcLen + 1
val resDigits = new Array[Int](resLen)
shiftLeftOneBit(resDigits, source.digits, srcLen)
val result = new BigInteger(source.sign, resLen, resDigits)
result.cutOffLeadingZeroes()
result
}
/** Shifts the source digits left one bit.
*
* Creates a value whose magnitude is doubled.
*
* @param result an array of digits that will hold the computed result when
* this method returns. The size of this array is {@code srcLen + 1},
* and the format is the same as {@link BigInteger#digits}.
* @param source the array of digits to shift left, in the same format as
* {@link BigInteger#digits}.
* @param srcLen the length of {@code source}; may be less than {@code source.length}
*/
def shiftLeftOneBit(result: Array[Int],
source: Array[Int],
srcLen: Int): Unit = {
var carry = 0
for (i <- 0 until srcLen) {
val iVal = source(i)
result(i) = (iVal << 1) | carry
carry = iVal >>> 31
}
if (carry != 0)
result(srcLen) = carry
}
/** @see BigInteger#shiftRight(int).
*
* @param source
* @param count
* @return
*/
def shiftRight(source: BigInteger, count: Int): BigInteger = {
val intCount: Int = count >> 5
val andCount: Int = count & 31 // count of remaining bits
if (intCount >= source.numberLength) {
if (source.sign < 0) BigInteger.MINUS_ONE
else BigInteger.ZERO
} else {
var resLength: Int = source.numberLength - intCount
val resDigits = new Array[Int](resLength + 1)
shiftRight(resDigits, resLength, source.digits, intCount, andCount)
if (source.sign < 0) {
// Checking if the dropped bits are zeros (the remainder equals to 0)
var i: Int = 0
while ((i < intCount) && (source.digits(i) == 0)) {
i += 1
}
// If the remainder is not zero, add 1 to the result
val cmp = (source.digits(i) << (32 - andCount)) != 0
if (i < intCount || (andCount > 0 && cmp)) {
i = 0
while (i < resLength && resDigits(i) == -1) {
resDigits(i) = 0
i += 1
}
if (i == resLength)
resLength += 1
resDigits(i) += 1
}
}
val result = new BigInteger(source.sign, resLength, resDigits)
result.cutOffLeadingZeroes()
result
}
}
/** Shifts right an array of integers.
*
* Total shift distance in bits is intCount * 32 + count.
*
* @param result the destination array
* @param resultLen the destination array's length
* @param source the source array
* @param intCount the number of elements to be shifted
* @param count the number of bits to be shifted
* @return dropped bit's are all zero (i.e. remaider is zero)
*/
def shiftRight(result: Array[Int],
resultLen: Int,
source: Array[Int],
intCount: Int,
count: Int): Boolean = {
var i: Int = 0
var allZero = true
while (i < intCount) {
allZero &= (source(i) == 0)
i += 1
}
if (count == 0) {
System.arraycopy(source, intCount, result, 0, resultLen)
} else {
val leftShiftCount = 32 - count
allZero &= ((source(i) << leftShiftCount) == 0)
i = 0
while (i < resultLen - 1) {
result(i) =
(source(i + intCount) >>> count) | (source(i + intCount + 1) << leftShiftCount)
i += 1
}
result(i) = source(i + intCount) >>> count
i += 1
}
allZero
}
/** Performs a fast bit testing for positive numbers.
*
* The bit to to be tested must be in the range {@code [0, val.bitLength()-1]}
*/
def testBit(bi: BigInteger, n: Int): Boolean =
(bi.digits(n >> 5) & (1 << (n & 31))) != 0
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy