| /* ==================================================================== |
| 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); |
| } |
| } |