123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /* ====================================================================
- 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.
- ==================================================================== */
-
- package org.apache.poi.ss.util;
-
- import java.math.BigInteger;
-
- final class MutableFPNumber {
-
-
- // TODO - what about values between (10<sup>14</sup>-0.5) and (10<sup>14</sup>-0.05) ?
- /**
- * The minimum value in 'Base-10 normalised form'.<br>
- * When {@link #_binaryExponent} == 46 this is the the minimum {@link #_frac} value
- * (10<sup>14</sup>-0.05) * 2^17
- * <br>
- * Values between (10<sup>14</sup>-0.05) and 10<sup>14</sup> will be represented as '1'
- * followed by 14 zeros.
- * Values less than (10<sup>14</sup>-0.05) will get shifted by one more power of 10
- *
- * This frac value rounds to '1' followed by fourteen zeros with an incremented decimal exponent
- */
- private static final BigInteger BI_MIN_BASE = new BigInteger("0B5E620F47FFFE666", 16);
- /**
- * For 'Base-10 normalised form'<br>
- * The maximum {@link #_frac} value when {@link #_binaryExponent} == 49
- * (10^15-0.5) * 2^14
- */
- private static final BigInteger BI_MAX_BASE = new BigInteger("0E35FA9319FFFE000", 16);
-
- /**
- * Width of a long
- */
- private static final int C_64 = 64;
-
- /**
- * Minimum precision after discarding whole 32-bit words from the significand
- */
- private static final int MIN_PRECISION = 72;
- private BigInteger _significand;
- private int _binaryExponent;
- public MutableFPNumber(BigInteger frac, int binaryExponent) {
- _significand = frac;
- _binaryExponent = binaryExponent;
- }
-
-
- public MutableFPNumber copy() {
- return new MutableFPNumber(_significand, _binaryExponent);
- }
- public void normalise64bit() {
- int oldBitLen = _significand.bitLength();
- int sc = oldBitLen - C_64;
- if (sc == 0) {
- return;
- }
- if (sc < 0) {
- throw new IllegalStateException("Not enough precision");
- }
- _binaryExponent += sc;
- if (sc > 32) {
- int highShift = (sc-1) & 0xFFFFE0;
- _significand = _significand.shiftRight(highShift);
- sc -= highShift;
- oldBitLen -= highShift;
- }
- if (sc < 1) {
- throw new IllegalStateException();
- }
- _significand = Rounder.round(_significand, sc);
- if (_significand.bitLength() > oldBitLen) {
- sc++;
- _binaryExponent++;
- }
- _significand = _significand.shiftRight(sc);
- }
- public int get64BitNormalisedExponent() {
- return _binaryExponent + _significand.bitLength() - C_64;
-
- }
-
- public boolean isBelowMaxRep() {
- int sc = _significand.bitLength() - C_64;
- return _significand.compareTo(BI_MAX_BASE.shiftLeft(sc)) < 0;
- }
- public boolean isAboveMinRep() {
- int sc = _significand.bitLength() - C_64;
- return _significand.compareTo(BI_MIN_BASE.shiftLeft(sc)) > 0;
- }
- public NormalisedDecimal createNormalisedDecimal(int pow10) {
- // missingUnderBits is (0..3)
- int missingUnderBits = _binaryExponent-39;
- int fracPart = (_significand.intValue() << missingUnderBits) & 0xFFFF80;
- long wholePart = _significand.shiftRight(C_64-_binaryExponent-1).longValue();
- return new NormalisedDecimal(wholePart, fracPart, pow10);
- }
- public void multiplyByPowerOfTen(int pow10) {
- TenPower tp = TenPower.getInstance(Math.abs(pow10));
- if (pow10 < 0) {
- mulShift(tp._divisor, tp._divisorShift);
- } else {
- mulShift(tp._multiplicand, tp._multiplierShift);
- }
- }
- private void mulShift(BigInteger multiplicand, int multiplierShift) {
- _significand = _significand.multiply(multiplicand);
- _binaryExponent += multiplierShift;
- // check for too much precision
- int sc = (_significand.bitLength() - MIN_PRECISION) & 0xFFFFFFE0;
- // mask makes multiples of 32 which optimises BigInteger.shiftRight
- if (sc > 0) {
- // no need to round because we have at least 8 bits of extra precision
- _significand = _significand.shiftRight(sc);
- _binaryExponent += sc;
- }
- }
-
- private static final class Rounder {
- private static final BigInteger[] HALF_BITS;
-
- static {
- BigInteger[] bis = new BigInteger[33];
- long acc=1;
- for (int i = 1; i < bis.length; i++) {
- bis[i] = BigInteger.valueOf(acc);
- acc <<=1;
- }
- HALF_BITS = bis;
- }
- /**
- * @param nBits number of bits to shift right
- */
- public static BigInteger round(BigInteger bi, int nBits) {
- if (nBits < 1) {
- return bi;
- }
- return bi.add(HALF_BITS[nBits]);
- }
- }
-
- /**
- * Holds values for quick multiplication and division by 10
- */
- private static final class TenPower {
- private static final BigInteger FIVE = BigInteger.valueOf(5);
- private static final TenPower[] _cache = new TenPower[350];
-
- public final BigInteger _multiplicand;
- public final BigInteger _divisor;
- public final int _divisorShift;
- public final int _multiplierShift;
-
- private TenPower(int index) {
- BigInteger fivePowIndex = FIVE.pow(index);
-
- int bitsDueToFiveFactors = fivePowIndex.bitLength();
- int px = 80 + bitsDueToFiveFactors;
- BigInteger fx = BigInteger.ONE.shiftLeft(px).divide(fivePowIndex);
- int adj = fx.bitLength() - 80;
- _divisor = fx.shiftRight(adj);
- bitsDueToFiveFactors -= adj;
-
- _divisorShift = -(bitsDueToFiveFactors+index+80);
- int sc = fivePowIndex.bitLength() - 68;
- if (sc > 0) {
- _multiplierShift = index + sc;
- _multiplicand = fivePowIndex.shiftRight(sc);
- } else {
- _multiplierShift = index;
- _multiplicand = fivePowIndex;
- }
- }
-
- static TenPower getInstance(int index) {
- TenPower result = _cache[index];
- if (result == null) {
- result = new TenPower(index);
- _cache[index] = result;
- }
- return result;
- }
- }
-
- public ExpandedDouble createExpandedDouble() {
- return new ExpandedDouble(_significand, _binaryExponent);
- }
- }
|