From 761565262a7b36277a20b290fe60d2e4c5460492 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Tue, 13 Oct 2009 23:24:14 +0000 Subject: [PATCH] Bugzilla 47969 - improvements to equals() methods git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@824972 13f79535-47bb-0310-9956-ffa450edef68 --- .../ss/formula/FormulaUsedBlankCellSet.java | 5 +- .../apache/poi/ss/formula/PlainCellCache.java | 1 + .../eval/forked/ForkedEvaluationSheet.java | 1 + .../apache/poi/ss/util/MutableFPNumber.java | 410 +++++++++--------- 4 files changed, 206 insertions(+), 211 deletions(-) diff --git a/src/java/org/apache/poi/ss/formula/FormulaUsedBlankCellSet.java b/src/java/org/apache/poi/ss/formula/FormulaUsedBlankCellSet.java index fc6d797237..91b2336e87 100644 --- a/src/java/org/apache/poi/ss/formula/FormulaUsedBlankCellSet.java +++ b/src/java/org/apache/poi/ss/formula/FormulaUsedBlankCellSet.java @@ -25,8 +25,8 @@ import java.util.Map; import org.apache.poi.hssf.util.CellReference; /** - * Optimisation - compacts many blank cell references used by a single formula. - * + * Optimisation - compacts many blank cell references used by a single formula. + * * @author Josh Micich */ final class FormulaUsedBlankCellSet { @@ -43,6 +43,7 @@ final class FormulaUsedBlankCellSet { return _bookIndex * 17 + _sheetIndex; } public boolean equals(Object obj) { + assert obj instanceof BookSheetKey : "these private cache key instances are only compared to themselves"; BookSheetKey other = (BookSheetKey) obj; return _bookIndex == other._bookIndex && _sheetIndex == other._sheetIndex; } diff --git a/src/java/org/apache/poi/ss/formula/PlainCellCache.java b/src/java/org/apache/poi/ss/formula/PlainCellCache.java index 957c73e011..967824bba6 100644 --- a/src/java/org/apache/poi/ss/formula/PlainCellCache.java +++ b/src/java/org/apache/poi/ss/formula/PlainCellCache.java @@ -52,6 +52,7 @@ final class PlainCellCache { } public boolean equals(Object obj) { + assert obj instanceof Loc : "these package-private cache key instances are only compared to themselves"; Loc other = (Loc) obj; return _bookSheetColumn == other._bookSheetColumn && _rowIndex == other._rowIndex; } diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java index 196bfa69dd..886919fe6e 100644 --- a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java +++ b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java @@ -111,6 +111,7 @@ final class ForkedEvaluationSheet implements EvaluationSheet { } @Override public boolean equals(Object obj) { + assert obj instanceof RowColKey : "these private cache key instances are only compared to themselves"; RowColKey other = (RowColKey) obj; return _rowIndex == other._rowIndex && _columnIndex == other._columnIndex; } diff --git a/src/java/org/apache/poi/ss/util/MutableFPNumber.java b/src/java/org/apache/poi/ss/util/MutableFPNumber.java index 2ae93e675c..50d872f676 100644 --- a/src/java/org/apache/poi/ss/util/MutableFPNumber.java +++ b/src/java/org/apache/poi/ss/util/MutableFPNumber.java @@ -1,209 +1,201 @@ -/* ==================================================================== - 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 (1014-0.5) and (1014-0.05) ? - /** - * The minimum value in 'Base-10 normalised form'.
- * When {@link #_binaryExponent} == 46 this is the the minimum {@link #_frac} value - * (1014-0.05) * 2^17 - *
- * Values between (1014-0.05) and 1014 will be represented as '1' - * followed by 14 zeros. - * Values less than (1014-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'
- * 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; - - } - - @Override - public boolean equals(Object obj) { - MutableFPNumber other = (MutableFPNumber) obj; - if (_binaryExponent != other._binaryExponent) { - return false; - } - return _significand.equals(other._significand); - } - 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 = new BigInteger("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); - } -} +/* ==================================================================== + 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 (1014-0.5) and (1014-0.05) ? + /** + * The minimum value in 'Base-10 normalised form'.
+ * When {@link #_binaryExponent} == 46 this is the the minimum {@link #_frac} value + * (1014-0.05) * 2^17 + *
+ * Values between (1014-0.05) and 1014 will be represented as '1' + * followed by 14 zeros. + * Values less than (1014-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'
+ * 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 = new BigInteger("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); + } +} -- 2.39.5