All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.math.BigInteger.scala Maven / Gradle / Ivy

The newest version!
/*
 * Ported by Alistair Johnson from
 * https://github.com/gwtproject/gwt/blob/master/user/super/com/google/gwt/emul/java/math/BigInteger.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

import java.util.Random
import scala.annotation.tailrec

object BigInteger {

  final val ONE = new BigInteger(1, 1)

  final val TEN = new BigInteger(1, 10)

  final val ZERO = new BigInteger(0, 0)

  private[math] final val EQUALS = 0

  /** The {@code BigInteger} constant 1 used for comparison. */
  private[math] final val GREATER = 1

  /** The {@code BigInteger} constant -1 used for comparison. */
  private[math] final val LESS = -1

  /** The {@code BigInteger} constant -1 used for comparison. */
  private[math] final val MINUS_ONE = new BigInteger(-1, 1)

  /** 2^32. */
  private final val POW32 = 4294967296d

  /** All the {@code BigInteger} numbers in the range [0,10] are cached. */
  private final val SMALL_VALUES = Array(
    ZERO,
    ONE,
    new BigInteger(1, 2),
    new BigInteger(1, 3),
    new BigInteger(1, 4),
    new BigInteger(1, 5),
    new BigInteger(1, 6),
    new BigInteger(1, 7),
    new BigInteger(1, 8),
    new BigInteger(1, 9),
    TEN
  )

  private final val TWO_POWS =
    Array.tabulate[BigInteger](32)(i => BigInteger.valueOf(1L << i))

  /** The first non zero digit is either -1 if sign is zero, otherwise it is >= 0.
   *
   *  Furthermore, it is a value that is often used and so the value computed from
   *  {@code getFirstNonzeroDigit} is cached  to {@code firstNonzeroDigit} and can be
   *  marked as unknown by a call to {@code unCache}. To mark the value as unknown,
   *  {@code firstNonzeroDigit} is set to the magic number {@code -2}
   */
  private final val firstNonzeroDigitNotSet = -2

  def probablePrime(bitLength: Int, rnd: Random): BigInteger =
    new BigInteger(bitLength, 100, rnd)

  def valueOf(lVal: Long): BigInteger = {
    if (lVal < 0) {
      if (lVal != -1) new BigInteger(-1, -lVal)
      else MINUS_ONE
    } else if (lVal <= 10) {
      SMALL_VALUES(lVal.toInt)
    } else {
      new BigInteger(1, lVal)
    }
  }

  private[math] def getPowerOfTwo(exp: Int): BigInteger = {
    if (exp < TWO_POWS.length) {
      TWO_POWS(exp)
    } else {
      val intCount  = exp >> 5
      val bitN      = exp & 31
      val resDigits = new Array[Int](intCount + 1)
      resDigits(intCount) = 1 << bitN
      new BigInteger(1, intCount + 1, resDigits)
    }
  }

  @inline
  private def checkNotNull[T <: AnyRef](reference: T): reference.type = {
    if (reference == null)
      throw new NullPointerException
    else
      reference
  }

  @inline
  private def checkCriticalArgument(expression: Boolean,
                                    errorMessage: => String): Unit = {
    if (!expression)
      throw new IllegalArgumentException(errorMessage)
  }

  @inline
  private[math] final class QuotAndRem(val quot: BigInteger,
                                       val rem: BigInteger) {
    def toArray(): Array[BigInteger] = Array[BigInteger](quot, rem)
  }
}

class BigInteger extends Number with Comparable[BigInteger] {
  import BigInteger._

  /** The magnitude of this big integer.
   *
   *  This array is in little endian order and each "digit" is a 32-bit unsigned
   *  integer. For example:
   *   - {@code 13} is represented as [ 13 ]
   *   - {@code -13} is represented as [ 13 ]
   *   - {@code 2^32 + 13} is represented as [ 13, 1 ]
   *   - {@code 2^64 + 13} is represented as [ 13, 0, 1 ]
   *   - {@code 2^31} is represented as [ Integer.MIN_VALUE ]
   *  The magnitude array may be longer than strictly necessary, which results
   *  in additional trailing zeros.
   */
  private[math] var digits: Array[Int] = _

  /** The length of this in measured in ints. Can be less than digits.length(). */
  private[math] var numberLength: Int = _

  /** The sign of this. */
  private[math] var sign: Int = _

  private var firstNonzeroDigit: Int = firstNonzeroDigitNotSet

  /** Cache for the hash code. */
  private var _hashCode: Int = 0

  def this(byteArray: Array[Byte]) = {
    this()
    if (byteArray.length == 0)
      throw new NumberFormatException("Zero length BigInteger")

    if (byteArray(0) < 0) {
      sign = -1
      this.putBytesNegativeToIntegers(byteArray)
    } else {
      sign = 1
      this.putBytesPositiveToIntegers(byteArray)
    }

    this.cutOffLeadingZeroes()
  }

  def this(signum: Int, magnitude: Array[Byte]) = {
    this()
    checkNotNull(magnitude)
    if ((signum < -1) || (signum > 1))
      throw new NumberFormatException("Invalid signum value")
    if (signum == 0 && magnitude.exists(_ != 0))
      throw new NumberFormatException("signum-magnitude mismatch")

    if (magnitude.length == 0) {
      sign = 0
      numberLength = 1
      digits = Array(0)
    } else {
      sign = signum
      this.putBytesPositiveToIntegers(magnitude)
      this.cutOffLeadingZeroes()
    }
  }

  def this(bitLength: Int, certainty: Int, rnd: Random) = {
    this()
    if (bitLength < 2)
      throw new ArithmeticException("bitLength < 2")

    val me = Primality.consBigInteger(bitLength, certainty, rnd)
    sign = me.sign
    numberLength = me.numberLength
    digits = me.digits
  }

  def this(numBits: Int, rnd: Random) = {
    this()
    checkCriticalArgument(numBits >= 0, "numBits must be non-negative")
    if (numBits == 0) {
      sign = 0
      numberLength = 1
      digits = Array(0)
    } else {
      sign = 1
      numberLength = (numBits + 31) >> 5
      digits = new Array[Int](numberLength)
      for (i <- 0 until numberLength) {
        digits(i) = rnd.nextInt()
      }
      digits(numberLength - 1) >>>= (-numBits) & 31
      this.cutOffLeadingZeroes()
    }
  }

  def this(s: String, radix: Int) = {
    this()
    checkNotNull(s)
    if ((radix < java.lang.Character.MIN_RADIX) ||
        (radix > java.lang.Character.MAX_RADIX))
      throw new NumberFormatException("Radix out of range")
    if (s.isEmpty)
      throw new NumberFormatException("Zero length BigInteger")

    this.setFromString(s, radix)
  }

  def this(s: String) = {
    this(s, 10)
  }

  /** Constructs a number which array is of size 1.
   *
   *  @param sign the sign of the number
   *  @param value the only one digit of array
   */
  private[math] def this(sign: Int, value: Int) = {
    this()
    this.sign = sign
    numberLength = 1
    digits = Array(value)
  }

  /** Creates a new {@code BigInteger} with the given sign and magnitude.
   *
   *  This constructor does not create a copy, so any changes to the reference will
   *  affect the new number.
   *
   *  @param signum The sign of the number represented by {@code digits}
   *  @param digits The magnitude of the number
   */
  private[math] def this(signum: Int, digits: Array[Int]) = {
    this()
    if (digits.length == 0) {
      this.sign = 0
      this.numberLength = 1
      this.digits = Array(0)
    } else {
      this.sign = signum
      this.numberLength = digits.length
      this.digits = digits
      this.cutOffLeadingZeroes()
    }
  }

  /** Constructs a number without to create new space.
   *
   *  This construct should be used only if the three fields of representation
   *  are known.
   *
   *  @param sign the sign of the number
   *  @param numberLength the length of the internal array
   *  @param digits a reference of some array created before
   */
  private[math] def this(sign: Int, numberLength: Int, digits: Array[Int]) = {
    this()
    this.sign = sign
    this.numberLength = numberLength
    this.digits = digits
  }

  /** Creates a new {@code BigInteger} with value equal to the specified {@code long}.
   *
   *  @param sign the sign of the number
   *  @param lVal the value of the new {@code BigInteger}.
   */
  private[math] def this(sign: Int, lVal: Long) = {
    this()
    this.sign = sign
    val hi = (lVal >>> 32).toInt
    if (hi == 0) {
      numberLength = 1
      digits = Array(lVal.toInt)
    } else {
      numberLength = 2
      digits = Array(lVal.toInt, hi)
    }
  }

  def abs(): BigInteger = {
    if (sign < 0) new BigInteger(1, numberLength, digits)
    else this
  }

  def add(bi: BigInteger): BigInteger = Elementary.add(this, bi)

  def and(bi: BigInteger): BigInteger = Logical.and(this, bi)

  def andNot(bi: BigInteger): BigInteger = Logical.andNot(this, bi)

  def bitCount(): Int = BitLevel.bitCount(this)

  def bitLength(): Int = BitLevel.bitLength(this)

  def clearBit(n: Int): BigInteger = {
    if (testBit(n)) BitLevel.flipBit(this, n)
    else this
  }

  def compareTo(bi: BigInteger): Int = {
    if (sign > bi.sign) GREATER
    else if (sign < bi.sign) LESS
    else if (numberLength > bi.numberLength) sign
    else if (numberLength < bi.numberLength) -bi.sign
    // else Equal sign and equal numberLength
    else sign * Elementary.compareArrays(digits, bi.digits, numberLength)
  }

  def divide(divisor: BigInteger): BigInteger = {
    if (divisor.sign == 0)
      throw new ArithmeticException("BigInteger divide by zero")

    val divisorSign = divisor.sign
    if (divisor.isOne) {
      if (divisor.sign > 0) this
      else this.negate()
    } else {
      val thisSign   = sign
      val thisLen    = numberLength
      val divisorLen = divisor.numberLength
      if (thisLen + divisorLen == 2) {
        var bi = (digits(0) & 0xFFFFFFFFL) / (divisor.digits(0) & 0xFFFFFFFFL)
        if (thisSign != divisorSign)
          bi = -bi
        valueOf(bi)
      } else {
        val cmp = {
          if (thisLen != divisorLen) {
            if (thisLen > divisorLen) 1
            else -1
          } else {
            Elementary.compareArrays(digits, divisor.digits, thisLen)
          }
        }

        if (cmp == EQUALS) {
          if (thisSign == divisorSign) ONE
          else MINUS_ONE
        } else if (cmp == LESS) {
          ZERO
        } else {
          val resLength = thisLen - divisorLen + 1
          val resDigits = new Array[Int](resLength)
          val resSign   = if (thisSign == divisorSign) 1 else -1
          if (divisorLen == 1) {
            Division
              .divideArrayByInt(resDigits, digits, thisLen, divisor.digits(0))
          } else {
            Division.divide(resDigits,
                            resLength,
                            digits,
                            thisLen,
                            divisor.digits,
                            divisorLen)
          }
          val result = new BigInteger(resSign, resLength, resDigits)
          result.cutOffLeadingZeroes()
          result
        }
      }
    }
  }

  def divideAndRemainder(divisor: BigInteger): Array[BigInteger] =
    divideAndRemainderImpl(divisor).toArray()

  private[math] def divideAndRemainderImpl(divisor: BigInteger): QuotAndRem = {
    val divisorSign = divisor.sign
    if (divisorSign == 0)
      throw new ArithmeticException("BigInteger divide by zero")

    val divisorLen    = divisor.numberLength
    val divisorDigits = divisor.digits
    if (divisorLen == 1) {
      Division.divideAndRemainderByInteger(this, divisorDigits(0), divisorSign)
    } else {
      // res[0] is a quotient and res[1] is a remainder:
      val thisDigits = digits
      val thisLen    = numberLength
      val cmp = {
        if (thisLen != divisorLen) {
          if (thisLen > divisorLen) 1
          else -1
        } else {
          Elementary.compareArrays(thisDigits, divisorDigits, thisLen)
        }
      }

      if (cmp < 0) {
        new QuotAndRem(ZERO, this)
      } else {
        val thisSign        = sign
        val quotientLength  = thisLen - divisorLen + 1
        val remainderLength = divisorLen
        val quotientSign    = if (thisSign == divisorSign) 1 else -1
        val quotientDigits  = new Array[Int](quotientLength)
        val remainderDigits = Division.divide(quotientDigits,
                                              quotientLength,
                                              thisDigits,
                                              thisLen,
                                              divisorDigits,
                                              divisorLen)
        val result0 =
          new BigInteger(quotientSign, quotientLength, quotientDigits)
        val result1 =
          new BigInteger(thisSign, remainderLength, remainderDigits)
        result0.cutOffLeadingZeroes()
        result1.cutOffLeadingZeroes()
        new QuotAndRem(result0, result1)
      }
    }
  }

  override def doubleValue(): Double =
    java.lang.Double.parseDouble(this.toString)

  override def equals(x: Any): Boolean = x match {
    case that: BigInteger =>
      this.sign == that.sign && this.numberLength == that.numberLength &&
        this.equalsArrays(that.digits)
    case _ => false
  }

  def flipBit(n: Int): BigInteger = {
    if (n < 0)
      throw new ArithmeticException("Negative bit address")

    BitLevel.flipBit(this, n)
  }

  override def floatValue(): Float =
    java.lang.Float.parseFloat(this.toString)

  def gcd(bi: BigInteger): BigInteger = {
    val val1 = this.abs()
    val val2 = bi.abs()
    // To avoid a possible division by zero
    if (val1.signum() == 0) {
      val2
    } else if (val2.signum() == 0) {
      val1
    } else if (((val1.numberLength == 1) && (val1.digits(0) > 0)) &&
               ((val2.numberLength == 1) && (val2.digits(0) > 0))) {
      // Optimization for small operands
      // (op2.bitLength() < 32) and (op1.bitLength() < 32)
      BigInteger.valueOf(Division.gcdBinary(val1.intValue(), val2.intValue()))
    } else {
      Division.gcdBinary(val1.copy(), val2.copy())
    }
  }

  def getLowestSetBit(): Int = {
    if (sign == 0) {
      -1
    } else {
      // (sign != 0) implies that exists some non zero digit
      val i = getFirstNonzeroDigit
      (i << 5) + java.lang.Integer.numberOfTrailingZeros(digits(i))
    }
  }

  override def hashCode(): Int = {
    if (_hashCode != 0) {
      _hashCode
    } else {
      for (i <- 0 until numberLength) {
        _hashCode = _hashCode * 33 + digits(i)
      }
      _hashCode = _hashCode * sign
      _hashCode
    }
  }

  override def intValue(): Int = sign * digits(0)

  def isProbablePrime(certainty: Int): Boolean =
    Primality.isProbablePrime(abs(), certainty)

  override def longValue(): Long = {
    val value =
      if (numberLength > 1)
        (digits(1).toLong << 32) | (digits(0) & 0xFFFFFFFFL)
      else digits(0) & 0xFFFFFFFFL
    sign * value
  }

  def max(bi: BigInteger): BigInteger = {
    if (this.compareTo(bi) == GREATER) this
    else bi
  }

  def min(bi: BigInteger): BigInteger = {
    if (this.compareTo(bi) == LESS) this
    else bi
  }

  def mod(m: BigInteger): BigInteger = {
    if (m.sign <= 0)
      throw new ArithmeticException("BigInteger: modulus not positive")

    val rem = remainder(m)
    if (rem.sign < 0) rem.add(m)
    else rem
  }

  def modInverse(m: BigInteger): BigInteger = {
    if (m.sign <= 0) {
      throw new ArithmeticException("BigInteger: modulus not positive")
    } else if (!(testBit(0) || m.testBit(0))) {
      // If both are even, no inverse exists
      throw new ArithmeticException("BigInteger not invertible.")
    } else if (m.isOne) {
      ZERO
    } else {
      // From now on: (m > 1)
      val res = Division.modInverseMontgomery(abs().mod(m), m)
      if (res.sign == 0)
        throw new ArithmeticException("BigInteger not invertible.")

      if (sign < 0) m.subtract(res)
      else res
    }
  }

  def modPow(exponent: BigInteger, m: BigInteger): BigInteger = {
    var _exponent = exponent
    if (m.sign <= 0)
      throw new ArithmeticException("BigInteger: modulus not positive")

    var base = this
    if (m.isOne || (_exponent.sign > 0 && base.sign == 0)) {
      BigInteger.ZERO
    } else if (base.sign == 0 && _exponent.sign == 0) {
      BigInteger.ONE
    } else {
      if (_exponent.sign < 0) {
        base = modInverse(m)
        _exponent = _exponent.negate()
      }
      // From now on: (m > 0) and (exponent >= 0)
      val res =
        if (m.testBit(0)) Division.oddModPow(base.abs(), _exponent, m)
        else Division.evenModPow(base.abs(), _exponent, m)
      if ((base.sign < 0) && _exponent.testBit(0))
        m.subtract(BigInteger.ONE).multiply(res).mod(m)
      else
        res
    }
  }

  def multiply(bi: BigInteger): BigInteger = {
    if (bi.sign == 0 || sign == 0) ZERO
    else Multiplication.multiply(this, bi)
  }

  def negate(): BigInteger = {
    if (sign == 0) this
    else new BigInteger(-sign, numberLength, digits)
  }

  def nextProbablePrime(): BigInteger = {
    if (sign < 0)
      throw new ArithmeticException("start < 0: " + this)

    Primality.nextProbablePrime(this)
  }

  def not(): BigInteger = Logical.not(this)

  def or(bi: BigInteger): BigInteger = Logical.or(this, bi)

  def pow(exp: Int): BigInteger =
    if (exp < 0) {
      throw new ArithmeticException("Negative exponent")
    } else if (exp == 0) {
      ONE
    } else if (exp == 1 || equals(ONE) || equals(ZERO)) {
      this
    } else if (!testBit(0)) {
      var x = 1
      while (!testBit(x)) {
        x += 1
      }
      getPowerOfTwo(x * exp).multiply(this.shiftRight(x).pow(exp))
    } else {
      // if even take out 2^x factor which we can calculate by shifting.
      Multiplication.pow(this, exp)
    }

  def remainder(divisor: BigInteger): BigInteger = {
    if (divisor.sign == 0)
      throw new ArithmeticException("BigInteger divide by zero")

    val thisLen    = numberLength
    val divisorLen = divisor.numberLength
    val cmp = {
      if (thisLen != divisorLen) {
        if (thisLen > divisorLen) 1
        else -1
      } else {
        Elementary.compareArrays(digits, divisor.digits, thisLen)
      }
    }

    if (cmp == LESS) {
      this
    } else {
      val resLength = divisorLen
      var resDigits = new Array[Int](resLength)
      if (resLength == 1) {
        resDigits(0) =
          Division.remainderArrayByInt(digits, thisLen, divisor.digits(0))
      } else {
        val qLen = thisLen - divisorLen + 1
        resDigits = Division
          .divide(null, qLen, digits, thisLen, divisor.digits, divisorLen)
      }
      val result = new BigInteger(sign, resLength, resDigits)
      result.cutOffLeadingZeroes()
      result
    }
  }

  def setBit(n: Int): BigInteger = {
    if (testBit(n)) this
    else BitLevel.flipBit(this, n)
  }

  def shiftLeft(n: Int): BigInteger = {
    if (n == 0 || sign == 0) this
    else if (n > 0) BitLevel.shiftLeft(this, n)
    else BitLevel.shiftRight(this, -n)
  }

  def shiftRight(n: Int): BigInteger = {
    if (n == 0 || sign == 0) this
    else if (n > 0) BitLevel.shiftRight(this, n)
    else BitLevel.shiftLeft(this, -n)
  }

  def signum(): Int = sign

  def subtract(bi: BigInteger): BigInteger = Elementary.subtract(this, bi)

  def testBit(n: Int): Boolean = {
    val intCount = n >> 5

    if (n == 0) {
      (digits(0) & 1) != 0
    } else if (n < 0) {
      throw new ArithmeticException("Negative bit address")
    } else if (intCount >= numberLength) {
      sign < 0
    } else if (sign < 0 && intCount < getFirstNonzeroDigit) {
      false
    } else {
      var digit = digits(intCount)
      if (sign < 0)
        digit = if (getFirstNonzeroDigit == intCount) -digit else ~digit
      val i = 1 << (n & 31)
      (digit & i) != 0
    }
  }

  def toByteArray(): Array[Byte] = {
    if (this.sign == 0)
      return Array[Byte](0) // scalastyle:ignore

    val temp: BigInteger  = this
    val bitLen            = bitLength()
    val firstNonZeroDigit = getFirstNonzeroDigit
    var bytesLen          = (bitLen >> 3) + 1
    /*
     * Puts the little-endian int array representing the magnitude of this
     * BigInteger into the big-endian byte array.
     */
    val bytes           = new Array[Byte](bytesLen)
    var firstByteNumber = 0
    var digitIndex      = firstNonZeroDigit
    var bytesInInteger  = 4
    var digit: Int      = 0

    val highBytes: Int = {
      if (bytesLen - (numberLength << 2) == 1) {
        val bytesZero = if (sign < 0) -1 else 0
        bytes(0) = bytesZero.toByte
        firstByteNumber += 1
        4
      } else {
        val hB: Int = bytesLen & 3
        if (hB == 0) 4
        else hB
      }
    }

    @inline
    @tailrec
    def loopBytes(tempDigit: Int => Unit): Unit = {
      if (bytesLen > firstByteNumber) {
        tempDigit(digitIndex)
        loopBytes(tempDigit)
      }
    }

    @inline
    def setBytesForDigit(tempDigit: Int): Unit = {
      digit = tempDigit
      digitIndex += 1
      if (digitIndex == numberLength)
        bytesInInteger = highBytes
      for (i <- 0 until bytesInInteger) {
        bytesLen -= 1
        bytes(bytesLen) = digit.toByte
        digit >>= 8
      }
    }

    bytesLen -= firstNonZeroDigit << 2
    if (sign < 0) {
      setBytesForDigit(-temp.digits(digitIndex))
      loopBytes(i => setBytesForDigit(~temp.digits(i)))
    } else {
      loopBytes(i => setBytesForDigit(temp.digits(i)))
    }
    bytes
  }

  override def toString(): String =
    Conversion.toDecimalScaledString(this)

  def toString(radix: Int): String =
    Conversion.bigInteger2String(this, radix)

  def xor(bi: BigInteger): BigInteger = Logical.xor(this, bi)

  /** Returns a copy of the current instance to achieve immutability. */
  private[math] def copy(): BigInteger = {
    val copyDigits = new Array[Int](numberLength)
    System.arraycopy(digits, 0, copyDigits, 0, numberLength)
    new BigInteger(sign, numberLength, copyDigits)
  }

  private[math] def cutOffLeadingZeroes(): Unit = {
    @inline
    @tailrec
    def loop(): Unit = {
      if (numberLength > 0) {
        numberLength -= 1
        if (digits(numberLength) == 0) loop()
      }
    }

    loop()
    if (digits(numberLength) == 0) {
      sign = 0
    }
    numberLength += 1
  }

  private[math] def equalsArrays(b: Array[Int]): Boolean =
    (0 until numberLength).forall(i => digits(i) == b(i))

  private[math] def getFirstNonzeroDigit(): Int = {
    if (firstNonzeroDigit == firstNonzeroDigitNotSet) {
      firstNonzeroDigit = {
        if (this.sign == 0) {
          -1
        } else {
          var i = 0
          while (digits(i) == 0) {
            i += 1
          }
          i
        }
      }
    }
    firstNonzeroDigit
  }

  /** Tests if {@code this.abs()} is equals to {@code ONE}. */
  private[math] def isOne(): Boolean =
    numberLength == 1 && digits(0) == 1

  private[math] def shiftLeftOneBit(): BigInteger = {
    if (sign == 0) this
    else BitLevel.shiftLeftOneBit(this)
  }

  private[math] def unCache(): Unit =
    firstNonzeroDigit = firstNonzeroDigitNotSet

  /** Puts a big-endian byte array into a little-endian applying two complement. */
  private def putBytesNegativeToIntegers(byteValues: Array[Byte]): Unit = {
    var bytesLen  = byteValues.length
    val highBytes = bytesLen & 3
    numberLength = (bytesLen >> 2) + (if (highBytes == 0) 0 else 1)
    digits = new Array[Int](numberLength)
    var i = 0
    // Setting the sign
    digits(numberLength - 1) = -1
    // Put bytes to the int array starting from the end of the byte array

    @inline
    @tailrec
    def loop(): Unit = if (bytesLen > highBytes) {
      digits(i) =
        (byteValues(bytesLen - 1) & 0xFF) |
          (byteValues(bytesLen - 2) & 0xFF) << 8 |
          (byteValues(bytesLen - 3) & 0xFF) << 16 |
          (byteValues(bytesLen - 4) & 0xFF) << 24
      bytesLen -= 4
      if (digits(i) != 0) {
        digits(i) = -digits(i)
        firstNonzeroDigit = i
        i += 1
        while (bytesLen > highBytes) {
          digits(i) =
            (byteValues(bytesLen - 1) & 0xFF) |
              (byteValues(bytesLen - 2) & 0xFF) << 8 |
              (byteValues(bytesLen - 3) & 0xFF) << 16 |
              (byteValues(bytesLen - 4) & 0xFF) << 24
          bytesLen -= 4
          digits(i) = ~digits(i)
          i += 1
        }
      } else {
        i += 1
        loop()
      }
    }

    loop()
    if (highBytes != 0) {
      // Put the first bytes in the highest element of the int array
      if (firstNonzeroDigit != firstNonzeroDigitNotSet) {
        for (j <- 0 until bytesLen) {
          digits(i) = (digits(i) << 8) | (byteValues(j) & 0xFF)
        }
        digits(i) = ~digits(i)
      } else {
        for (j <- 0 until bytesLen) {
          digits(i) = (digits(i) << 8) | (byteValues(j) & 0xFF)
        }
        digits(i) = -digits(i)
      }
    }
  }

  /** Puts a big-endian byte array into a little-endian int array. */
  private def putBytesPositiveToIntegers(byteValues: Array[Byte]): Unit = {
    var bytesLen  = byteValues.length
    val highBytes = bytesLen & 3
    numberLength = (bytesLen >> 2) + (if (highBytes == 0) 0 else 1)
    digits = new Array[Int](numberLength)

    // Put bytes to the int array starting from the end of the byte array
    var i = 0
    while (bytesLen > highBytes) {
      digits(i) =
        (byteValues(bytesLen - 1) & 0xFF) |
          (byteValues(bytesLen - 2) & 0xFF) << 8 |
          (byteValues(bytesLen - 3) & 0xFF) << 16 |
          (byteValues(bytesLen - 4) & 0xFF) << 24
      bytesLen = bytesLen - 4
      i += 1
    }
    // Put the first bytes in the highest element of the int array
    for (j <- 0 until bytesLen) {
      digits(i) = (digits(i) << 8) | (byteValues(j) & 0xFF)
    }
  }

  /** @see BigInteger#BigInteger(String, int). */
  private def setFromString(s: String, radix: Int): Unit = {
    if (s == "" || s == "+" || s == "-")
      throw new NumberFormatException("Zero length BigInteger")

    val stringLength0 = s.length
    val endChar       = stringLength0
    val (_sign, startChar, stringLength) = {
      if (s.charAt(0) == '-') (-1, 1, stringLength0 - 1)
      else if (s.charAt(0) == '+') (1, 1, stringLength0 - 1)
      else (1, 0, stringLength0)
    }

    // Validate that there are no further sign characters
    for (i <- startChar until stringLength0) {
      val c = s.charAt(i)
      if (c == '+' || c == '-')
        throw new NumberFormatException("Illegal embedded sign character")
    }

    /*
     * We use the following algorithm: split a string into portions of n
     * characters and convert each portion to an integer according to the radix.
     * Then convert an exp(radix, n) based number to binary using the
     * multiplication method. See D. Knuth, The Art of Computer Programming,
     * vol. 2.
     */
    val charsPerInt          = Conversion.DigitFitInInt(radix)
    var bigRadixDigitsLength = stringLength / charsPerInt
    val topChars             = stringLength % charsPerInt
    if (topChars != 0)
      bigRadixDigitsLength += 1

    val _digits       = new Array[Int](bigRadixDigitsLength)
    val bigRadix      = Conversion.BigRadices(radix - 2)
    var digitIndex    = 0
    var substrEnd     = startChar + (if (topChars == 0) charsPerInt else topChars)
    var newDigit: Int = 0
    var substrStart   = startChar
    while (substrStart < endChar) {
      val bigRadixDigit =
        java.lang.Integer.parseInt(s.substring(substrStart, substrEnd), radix)
      newDigit = Multiplication.multiplyByInt(_digits, digitIndex, bigRadix)
      newDigit += Elementary.inplaceAdd(_digits, digitIndex, bigRadixDigit)
      _digits(digitIndex) = newDigit
      digitIndex += 1
      substrStart = substrEnd
      substrEnd = substrStart + charsPerInt
    }

    this.sign = _sign
    this.numberLength = digitIndex
    this.digits = _digits
    this.cutOffLeadingZeroes()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy