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

com.upokecenter.numbers.NumberUtility Maven / Gradle / Ivy

Go to download

A Java library that supports arbitrary-precision binary and decimal floating-point numbers and rational numbers with arbitrary-precision components, and supports arithmetic with these numbers.

There is a newer version: 1.8.2
Show newest version
package com.upokecenter.numbers;
/*
Written by Peter O. in 2013.
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
If you like this, you should donate to Peter O.
at: http://peteroupc.github.io/
 */

  final class NumberUtility {
private NumberUtility() {
}
    private static final EInteger[] ValueBigIntPowersOfTen = {
      EInteger.FromInt32(1), EInteger.FromInt32(10), EInteger.FromInt64(100), EInteger.FromInt64(1000),
      EInteger.FromInt64(10000), EInteger.FromInt64(100000), EInteger.FromInt64(1000000),
      EInteger.FromInt64(10000000), EInteger.FromInt64(100000000), EInteger.FromInt64(1000000000),
      EInteger.FromInt64(10000000000L), EInteger.FromInt64(100000000000L),
      EInteger.FromInt64(1000000000000L), EInteger.FromInt64(10000000000000L),
      EInteger.FromInt64(100000000000000L), EInteger.FromInt64(1000000000000000L),
      EInteger.FromInt64(10000000000000000L),
      EInteger.FromInt64(100000000000000000L), EInteger.FromInt64(1000000000000000000L)
    };

    private static final EInteger[] ValueBigIntPowersOfFive = {
      EInteger.FromInt32(1), EInteger.FromInt64(5), EInteger.FromInt64(25), EInteger.FromInt64(125),
      EInteger.FromInt64(625), EInteger.FromInt64(3125), EInteger.FromInt64(15625),
      EInteger.FromInt64(78125), EInteger.FromInt64(390625),
      EInteger.FromInt64(1953125), EInteger.FromInt64(9765625), EInteger.FromInt64(48828125),
      EInteger.FromInt64(244140625), EInteger.FromInt64(1220703125),
      EInteger.FromInt64(6103515625L), EInteger.FromInt64(30517578125L),
      EInteger.FromInt64(152587890625L), EInteger.FromInt64(762939453125L),
      EInteger.FromInt64(3814697265625L), EInteger.FromInt64(19073486328125L),
      EInteger.FromInt64(95367431640625L),
      EInteger.FromInt64(476837158203125L), EInteger.FromInt64(2384185791015625L),
      EInteger.FromInt64(11920928955078125L),
      EInteger.FromInt64(59604644775390625L), EInteger.FromInt64(298023223876953125L),
      EInteger.FromInt64(1490116119384765625L), EInteger.FromInt64(7450580596923828125L)
    };

    static int ShiftLeftOne(int[] arr) {
      {
        int carry = 0;
        for (int i = 0; i < arr.length; ++i) {
          int item = arr[i];
          arr[i] = (int)(arr[i] << 1) | (int)carry;
          carry = ((item >> 31) != 0) ? 1 : 0;
        }
        return carry;
      }
    }

    private static int CountTrailingZeros(int numberValue) {
      if (numberValue == 0) {
        return 32;
      }
      int i = 0;
      {
        if ((numberValue << 16) == 0) {
          numberValue >>= 16;
          i += 16;
        }
        if ((numberValue << 24) == 0) {
          numberValue >>= 8;
          i += 8;
        }
        if ((numberValue << 28) == 0) {
          numberValue >>= 4;
          i += 4;
        }
        if ((numberValue << 30) == 0) {
          numberValue >>= 2;
          i += 2;
        }
        if ((numberValue << 31) == 0) {
          ++i;
        }
      }
      return i;
    }

    static int BitPrecisionInt(int numberValue) {
      if (numberValue == 0) {
        return 0;
      }
      int i = 32;
      {
        if ((numberValue >> 16) == 0) {
          numberValue <<= 16;
          i -= 8;
        }
        if ((numberValue >> 24) == 0) {
          numberValue <<= 8;
          i -= 8;
        }
        if ((numberValue >> 28) == 0) {
          numberValue <<= 4;
          i -= 4;
        }
        if ((numberValue >> 30) == 0) {
          numberValue <<= 2;
          i -= 2;
        }
        if ((numberValue >> 31) == 0) {
          --i;
        }
      }
      return i;
    }

    static int ShiftAwayTrailingZerosTwoElements(int[] arr) {
      int a0 = arr[0];
      int a1 = arr[1];
      int tz = CountTrailingZeros(a0);
      if (tz == 0) {
        return 0;
      }
      {
        if (tz < 32) {
          int carry = a1 << (32 - tz);
          arr[0] = (int)((a0 >> tz) & (0x7fffffff >> (tz - 1))) | (int)carry;
          arr[1] = (a1 >> tz) & (0x7fffffff >> (tz - 1));
          return tz;
        }
        tz = CountTrailingZeros(a1);
        if (tz == 32) {
          arr[0] = 0;
        } else if (tz > 0) {
          arr[0] = (a1 >> tz) & (0x7fffffff >> (tz - 1));
        } else {
          arr[0] = a1;
        }
        arr[1] = 0;
        return 32 + tz;
      }
    }

    static boolean HasBitSet(int[] arr, int bit) {
      return (bit >> 5) < arr.length && (arr[bit >> 5] & (1 << (bit & 31))) !=
      0;
    }

    private static final class PowerCache {
      private static final int MaxSize = 128;
      private final EInteger[] outputs;
      private final EInteger[] inputs;
      private final int[] inputsInts;

      public PowerCache() {
        this.outputs = new EInteger[MaxSize];
        this.inputs = new EInteger[MaxSize];
        this.inputsInts = new int[MaxSize];
      }

      private int size;

      public EInteger[] FindCachedPowerOrSmaller(EInteger bi) {
        EInteger[] ret = null;
        EInteger minValue = null;
        if (bi.CanFitInInt32()) {
          return this.FindCachedPowerIntOrSmaller(bi.ToInt32Checked());
        }
        synchronized (this.outputs) {
          for (int i = 0; i < this.size; ++i) {
            if (this.inputs[i].compareTo(bi) <= 0 && (minValue == null ||
            this.inputs[i].compareTo(minValue) >= 0)) {
   // DebugUtility.Log("Have cached power (" + inputs[i] + "," + bi + ") ");
              ret = new EInteger[2];
              ret[0] = this.inputs[i];
              ret[1] = this.outputs[i];
              minValue = this.inputs[i];
            }
          }
        }
        return ret;
      }

      public EInteger[] FindCachedPowerIntOrSmaller(int precision) {
        EInteger[] ret = null;
        int integerMinValue = -1;
        synchronized (this.outputs) {
          for (int i = 0; i < this.size; ++i) {
            if (this.inputsInts[i] >= 0 &&
                this.inputsInts[i] <= precision && (integerMinValue == -1 ||
            this.inputsInts[i] >= integerMinValue)) {
   // DebugUtility.Log("Have cached power (" + inputs[i] + "," + bi + ") ");
              ret = new EInteger[2];
              ret[0] = this.inputs[i];
              ret[1] = this.outputs[i];
              integerMinValue = this.inputsInts[i];
            }
          }
        }
        return ret;
      }

      public EInteger GetCachedPower(EInteger bi) {
        if (bi.CanFitInInt32()) {
          return this.GetCachedPowerInt(bi.ToInt32Checked());
        }
        synchronized (this.outputs) {
          for (int i = 0; i < this.size; ++i) {
            if (bi.equals(this.inputs[i])) {
              if (i != 0) {
                EInteger tmp;
                // Move to head of cache if it isn't already
                tmp = this.inputs[i]; this.inputs[i] = this.inputs[0];
                this.inputs[0] = tmp;
                int tmpi = this.inputsInts[i]; this.inputsInts[i] =
                this.inputsInts[0]; this.inputsInts[0] = tmpi;
                tmp = this.outputs[i]; this.outputs[i] = this.outputs[0];
                this.outputs[0] = tmp;
                // Move formerly newest to next newest
                if (i != 1) {
                  tmp = this.inputs[i]; this.inputs[i] = this.inputs[1];
                  this.inputs[1] = tmp;
                  tmpi = this.inputsInts[i]; this.inputsInts[i] =
                  this.inputsInts[1]; this.inputsInts[1] = tmpi;
                  tmp = this.outputs[i]; this.outputs[i] = this.outputs[1];
                  this.outputs[1] = tmp;
                }
              }
              return this.outputs[0];
            }
          }
        }
        return null;
      }

      public EInteger GetCachedPowerInt(int bi) {
        synchronized (this.outputs) {
          for (int i = 0; i < this.size; ++i) {
            if (this.inputsInts[i] >= 0 && this.inputsInts[i] == bi) {
              if (i != 0) {
                EInteger tmp;
                // Move to head of cache if it isn't already
                tmp = this.inputs[i]; this.inputs[i] = this.inputs[0];
                this.inputs[0] = tmp;
                int tmpi = this.inputsInts[i]; this.inputsInts[i] =
                this.inputsInts[0]; this.inputsInts[0] = tmpi;
                tmp = this.outputs[i]; this.outputs[i] = this.outputs[0];
                this.outputs[0] = tmp;
                // Move formerly newest to next newest
                if (i != 1) {
                  tmp = this.inputs[i]; this.inputs[i] = this.inputs[1];
                  this.inputs[1] = tmp;
                  tmpi = this.inputsInts[i]; this.inputsInts[i] =
                  this.inputsInts[1]; this.inputsInts[1] = tmpi;
                  tmp = this.outputs[i]; this.outputs[i] = this.outputs[1];
                  this.outputs[1] = tmp;
                }
              }
              return this.outputs[0];
            }
          }
        }
        return null;
      }

      public void AddPower(EInteger input, EInteger output) {
        synchronized (this.outputs) {
          if (this.size < MaxSize) {
            // Shift newer entries down
            for (int i = this.size; i > 0; --i) {
              this.inputs[i] = this.inputs[i - 1];
              this.inputsInts[i] = this.inputsInts[i - 1];
              this.outputs[i] = this.outputs[i - 1];
            }
            this.inputs[0] = input;
       this.inputsInts[0] = input.CanFitInInt32() ? input.ToInt32Checked() : -1;
            this.outputs[0] = output;
            ++this.size;
          } else {
            // Shift newer entries down
            for (int i = MaxSize - 1; i > 0; --i) {
              this.inputs[i] = this.inputs[i - 1];
              this.inputsInts[i] = this.inputsInts[i - 1];
              this.outputs[i] = this.outputs[i - 1];
            }
            this.inputs[0] = input;
       this.inputsInts[0] = input.CanFitInInt32() ? input.ToInt32Checked() : -1;
            this.outputs[0] = output;
          }
        }
      }
    }

    private static final PowerCache ValuePowerOfFiveCache = new
    NumberUtility.PowerCache();

    private static final PowerCache ValuePowerOfTenCache = new
      NumberUtility.PowerCache();

    static EInteger FindPowerOfFiveFromBig(EInteger diff) {
      int sign = diff.signum();
      if (sign < 0) {
        return EInteger.FromInt32(0);
      }
      if (sign == 0) {
        return EInteger.FromInt32(1);
      }
      FastInteger intcurexp = FastInteger.FromBig(diff);
      if (intcurexp.CompareToInt(54) <= 0) {
        return FindPowerOfFive(intcurexp.AsInt32());
      }
      // DebugUtility.Log("Getting power of five from big "+diff);
      EInteger mantissa = EInteger.FromInt32(1);
      EInteger bigpow;
      EInteger origdiff = diff;
      bigpow = ValuePowerOfFiveCache.GetCachedPower(origdiff);
      if (bigpow != null) {
        return bigpow;
      }
      EInteger[] otherPower =
      ValuePowerOfFiveCache.FindCachedPowerOrSmaller(origdiff);
      if (otherPower != null) {
        // DebugUtility.Log("Found cached power " +otherPower[0]+", "
        // +otherPower[1]);
        intcurexp.SubtractBig(otherPower[0]);
        bigpow = otherPower[1];
        mantissa = bigpow;
      } else {
        bigpow = EInteger.FromInt32(0);
      }
      while (intcurexp.signum() > 0) {
        if (intcurexp.CompareToInt(27) <= 0) {
          bigpow = FindPowerOfFive(intcurexp.AsInt32());
          mantissa = mantissa.Multiply(bigpow);
          break;
        }
        if (intcurexp.CompareToInt(9999999) <= 0) {
          int icurexp = intcurexp.AsInt32();
          int halficurexp = icurexp / 2;
          bigpow = FindPowerOfFive(halficurexp);
          bigpow = bigpow.Multiply(
           FindPowerOfFive(icurexp - halficurexp));
          mantissa = mantissa.Multiply(bigpow);
          break;
        }
        if (bigpow.isZero()) {
          bigpow = FindPowerOfFive(1).Pow(9999999);
        }
        mantissa = mantissa.Multiply(bigpow);
        intcurexp.AddInt(-9999999);
      }
      ValuePowerOfFiveCache.AddPower(origdiff, mantissa);
      return mantissa;
    }

    private static final EInteger ValueBigInt36 = EInteger.FromInt64(36);

    static EInteger FindPowerOfTenFromBig(EInteger
    bigintExponent) {
      int sign = bigintExponent.signum();
      if (sign < 0) {
        return EInteger.FromInt32(0);
      }
      if (sign == 0) {
        return EInteger.FromInt32(1);
      }
      if (bigintExponent.compareTo(ValueBigInt36) <= 0) {
        return FindPowerOfTen(bigintExponent.ToInt32Checked());
      }
      FastInteger intcurexp = FastInteger.FromBig(bigintExponent);
      EInteger mantissa = EInteger.FromInt32(1);
      EInteger bigpow = EInteger.FromInt32(0);
      // DebugUtility.Log("Getting power of ten from big "+bigintExponent);
      while (intcurexp.signum() > 0) {
        if (intcurexp.CompareToInt(18) <= 0) {
          bigpow = FindPowerOfTen(intcurexp.AsInt32());
          mantissa = mantissa.Multiply(bigpow);
          break;
        }
        if (intcurexp.CompareToInt(9999999) <= 0) {
          int val = intcurexp.AsInt32();
          bigpow = FindPowerOfFive(val);
          bigpow = bigpow.ShiftLeft(val);
          mantissa = mantissa.Multiply(bigpow);
          break;
        }
        if (bigpow.isZero()) {
          bigpow = FindPowerOfFive(9999999);
          bigpow = bigpow.ShiftLeft(9999999);
        }
        mantissa = mantissa.Multiply(bigpow);
        intcurexp.AddInt(-9999999);
      }
      return mantissa;
    }

    private static final EInteger ValueFivePower40 =
    (EInteger.FromInt64(95367431640625L)).Multiply(EInteger.FromInt64(95367431640625L));

    static EInteger FindPowerOfFive(int precision) {
      if (precision < 0) {
        return EInteger.FromInt32(0);
      }
      if (precision <= 27) {
        return ValueBigIntPowersOfFive[(int)precision];
      }
      EInteger bigpow;
      EInteger ret;
      if (precision == 40) {
        return ValueFivePower40;
      }
      int startPrecision = precision;
      bigpow = ValuePowerOfFiveCache.GetCachedPowerInt(precision);
      if (bigpow != null) {
        return bigpow;
      }
      EInteger origPrecision = EInteger.FromInt32(precision);
      // DebugUtility.Log("Getting power of five "+precision);
      if (precision <= 54) {
        if ((precision & 1) == 0) {
          ret = ValueBigIntPowersOfFive[(int)(precision >> 1)];
          ret = ret.Multiply(ret);
          ValuePowerOfFiveCache.AddPower(origPrecision, ret);
          return ret;
        }
        ret = ValueBigIntPowersOfFive[27];
        bigpow = ValueBigIntPowersOfFive[((int)precision) - 27];
        ret = ret.Multiply(bigpow);
        ValuePowerOfFiveCache.AddPower(origPrecision, ret);
        return ret;
      }
      if (precision > 40 && precision <= 94) {
        ret = ValueFivePower40;
        bigpow = FindPowerOfFive(precision - 40);
        ret = ret.Multiply(bigpow);
        ValuePowerOfFiveCache.AddPower(origPrecision, ret);
        return ret;
      }
      EInteger[] otherPower;
      boolean first = true;
      bigpow = EInteger.FromInt32(0);
      while (true) {
        otherPower =
        ValuePowerOfFiveCache.FindCachedPowerIntOrSmaller(precision);
        if (otherPower != null) {
          EInteger otherPower0 = otherPower[0];
          EInteger otherPower1 = otherPower[1];
          precision -= otherPower0.ToInt32Checked();
          if (first) {
            bigpow = otherPower[1];
          } else {
            bigpow = bigpow.Multiply(otherPower1);
          }
          first = false;
        } else {
          break;
        }
      }
      ret = !first ? bigpow : EInteger.FromInt32(1);
      while (precision > 0) {
        if (precision <= 27) {
          bigpow = ValueBigIntPowersOfFive[(int)precision];
          if (first) {
            ret = bigpow;
          } else {
            ret = ret.Multiply(bigpow);
          }
          first = false;
          break;
        }
        if (precision <= 9999999) {
          // DebugUtility.Log("calcing pow for "+precision);
          bigpow = ValueBigIntPowersOfFive[1].Pow(precision);
          if (precision != startPrecision) {
            EInteger bigprec = EInteger.FromInt32(precision);
            ValuePowerOfFiveCache.AddPower(bigprec, bigpow);
          }
          if (first) {
            ret = bigpow;
          } else {
            ret = ret.Multiply(bigpow);
          }
          first = false;
          break;
        }
        if (bigpow.isZero()) {
          bigpow = FindPowerOfFive(9999999);
        }
        if (first) {
          ret = bigpow;
        } else {
          ret = ret.Multiply(bigpow);
        }
        first = false;
        precision -= 9999999;
      }
      ValuePowerOfFiveCache.AddPower(origPrecision, ret);
      return ret;
    }

    static EInteger FindPowerOfTen(int precision) {
      if (precision < 0) {
        return EInteger.FromInt32(0);
      }
      if (precision <= 18) {
        return ValueBigIntPowersOfTen[(int)precision];
      }
      EInteger bigpow;
      EInteger ret;
      int startPrecision = precision;
      bigpow = ValuePowerOfTenCache.GetCachedPowerInt(precision);
      if (bigpow != null) {
        return bigpow;
      }
      EInteger origPrecision = EInteger.FromInt32(precision);
      if (precision <= 27) {
        int prec = (int)precision;
        ret = ValueBigIntPowersOfFive[prec];
        ret = ret.ShiftLeft(prec);
        ValuePowerOfTenCache.AddPower(origPrecision, ret);
        return ret;
      }
      if (precision <= 36) {
        if ((precision & 1) == 0) {
          ret = ValueBigIntPowersOfTen[(int)(precision >> 1)];
          ret = ret.Multiply(ret);
          ValuePowerOfTenCache.AddPower(origPrecision, ret);
          return ret;
        }
        ret = ValueBigIntPowersOfTen[18];
        bigpow = ValueBigIntPowersOfTen[((int)precision) - 18];
        ret = ret.Multiply(bigpow);
        ValuePowerOfTenCache.AddPower(origPrecision, ret);
        return ret;
      }
      EInteger[] otherPower;
      boolean first = true;
      bigpow = EInteger.FromInt32(0);
      while (true) {
        otherPower =
        ValuePowerOfTenCache.FindCachedPowerOrSmaller(EInteger.FromInt32(precision));
        if (otherPower != null) {
          EInteger otherPower0 = otherPower[0];
          EInteger otherPower1 = otherPower[1];
          // if (precision != otherPower0.ToInt32Checked()) {
            // DebugUtility.Log("bigcachedpower miss {0} -> {1}"
            // , precision, otherPower0);
          // }
          precision -= otherPower0.ToInt32Checked();
          if (first) {
            bigpow = otherPower[1];
          } else {
            bigpow = bigpow.Multiply(otherPower1);
          }
          first = false;
        } else {
          break;
        }
      }
      ret = !first ? bigpow : EInteger.FromInt32(1);
      while (precision > 0) {
        if (precision <= 18) {
          bigpow = ValueBigIntPowersOfTen[(int)precision];
          if (first) {
            ret = bigpow;
          } else {
            ret = ret.Multiply(bigpow);
          }
          first = false;
          break;
        }
        if (precision <= 9999999) {
          // DebugUtility.Log("calcing pow for "+precision);
          bigpow = FindPowerOfFive(precision);
          bigpow = bigpow.ShiftLeft(precision);
          if (precision != startPrecision) {
            EInteger bigprec = EInteger.FromInt32(precision);
            ValuePowerOfTenCache.AddPower(bigprec, bigpow);
          }
          if (first) {
            ret = bigpow;
          } else {
            ret = ret.Multiply(bigpow);
          }
          first = false;
          break;
        }
        if (bigpow.isZero()) {
          bigpow = FindPowerOfTen(9999999);
        }
        if (first) {
          ret = bigpow;
        } else {
          ret = ret.Multiply(bigpow);
        }
        first = false;
        precision -= 9999999;
      }
      ValuePowerOfTenCache.AddPower(origPrecision, ret);
      return ret;
    }

    public static EInteger ReduceTrailingZeros(
      EInteger bigmant,
      FastInteger exponentMutable,
      int radix,
      FastInteger digits,
      FastInteger precision,
      FastInteger idealExp) {
      if (bigmant.isZero()) {
        exponentMutable.SetInt(0);
        return bigmant;
      }
      EInteger bigradix = EInteger.FromInt32(radix);
      int bitToTest = 0;
      FastInteger bitsToShift = new FastInteger(0);
      while (!bigmant.isZero()) {
        if (precision != null && digits.compareTo(precision) == 0) {
          break;
        }
        if (idealExp != null && exponentMutable.compareTo(idealExp) == 0) {
          break;
        }
        if (radix == 2) {
          if (bitToTest < Integer.MAX_VALUE) {
            if (bigmant.GetSignedBit(bitToTest)) {
              break;
            }
            ++bitToTest;
            bitsToShift.Increment();
          } else {
            if (!bigmant.isEven()) {
              break;
            }
            bigmant = bigmant.ShiftRight(1);
          }
        } else {
          EInteger bigrem;
          EInteger bigquo;
{
EInteger[] divrem = bigmant.DivRem(bigradix);
bigquo = divrem[0];
bigrem = divrem[1]; }
          if (!bigrem.isZero()) {
            break;
          }
          bigmant = bigquo;
        }
        exponentMutable.Increment();
        if (digits != null) {
          digits.Decrement();
        }
      }
      if (radix == 2 && !bitsToShift.isValueZero()) {
        while (bitsToShift.CompareToInt(1000000) > 0) {
          bigmant = bigmant.ShiftRight(1000000);
          bitsToShift.SubtractInt(1000000);
        }
        int tmpshift = bitsToShift.AsInt32();
        bigmant = bigmant.ShiftRight(tmpshift);
      }
      return bigmant;
    }
  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy