Bugzilla 47969 - improvements to equals() methods

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@824972 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-10-13 23:24:14 +00:00
parent af6a4745e2
commit 1833764495
4 changed files with 206 additions and 211 deletions

View File

@ -25,8 +25,8 @@ import java.util.Map;
import org.apache.poi.hssf.util.CellReference; 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 * @author Josh Micich
*/ */
final class FormulaUsedBlankCellSet { final class FormulaUsedBlankCellSet {
@ -43,6 +43,7 @@ final class FormulaUsedBlankCellSet {
return _bookIndex * 17 + _sheetIndex; return _bookIndex * 17 + _sheetIndex;
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
assert obj instanceof BookSheetKey : "these private cache key instances are only compared to themselves";
BookSheetKey other = (BookSheetKey) obj; BookSheetKey other = (BookSheetKey) obj;
return _bookIndex == other._bookIndex && _sheetIndex == other._sheetIndex; return _bookIndex == other._bookIndex && _sheetIndex == other._sheetIndex;
} }

View File

@ -52,6 +52,7 @@ final class PlainCellCache {
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
assert obj instanceof Loc : "these package-private cache key instances are only compared to themselves";
Loc other = (Loc) obj; Loc other = (Loc) obj;
return _bookSheetColumn == other._bookSheetColumn && _rowIndex == other._rowIndex; return _bookSheetColumn == other._bookSheetColumn && _rowIndex == other._rowIndex;
} }

View File

@ -111,6 +111,7 @@ final class ForkedEvaluationSheet implements EvaluationSheet {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
assert obj instanceof RowColKey : "these private cache key instances are only compared to themselves";
RowColKey other = (RowColKey) obj; RowColKey other = (RowColKey) obj;
return _rowIndex == other._rowIndex && _columnIndex == other._columnIndex; return _rowIndex == other._rowIndex && _columnIndex == other._columnIndex;
} }

View File

@ -1,209 +1,201 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0 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 not use this file except in compliance with
the License. You may obtain a copy of the License at the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.ss.util; package org.apache.poi.ss.util;
import java.math.BigInteger; import java.math.BigInteger;
final class MutableFPNumber { final class MutableFPNumber {
// TODO - what about values between (10<sup>14</sup>-0.5) and (10<sup>14</sup>-0.05) ? // 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/> * The minimum value in 'Base-10 normalised form'.<br/>
* When {@link #_binaryExponent} == 46 this is the the minimum {@link #_frac} value * When {@link #_binaryExponent} == 46 this is the the minimum {@link #_frac} value
* (10<sup>14</sup>-0.05) * 2^17 * (10<sup>14</sup>-0.05) * 2^17
* <br/> * <br/>
* Values between (10<sup>14</sup>-0.05) and 10<sup>14</sup> will be represented as '1' * Values between (10<sup>14</sup>-0.05) and 10<sup>14</sup> will be represented as '1'
* followed by 14 zeros. * followed by 14 zeros.
* Values less than (10<sup>14</sup>-0.05) will get shifted by one more power of 10 * 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 * 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); private static final BigInteger BI_MIN_BASE = new BigInteger("0B5E620F47FFFE666", 16);
/** /**
* For 'Base-10 normalised form'<br/> * For 'Base-10 normalised form'<br/>
* The maximum {@link #_frac} value when {@link #_binaryExponent} == 49 * The maximum {@link #_frac} value when {@link #_binaryExponent} == 49
* (10^15-0.5) * 2^14 * (10^15-0.5) * 2^14
*/ */
private static final BigInteger BI_MAX_BASE = new BigInteger("0E35FA9319FFFE000", 16); private static final BigInteger BI_MAX_BASE = new BigInteger("0E35FA9319FFFE000", 16);
/** /**
* Width of a long * Width of a long
*/ */
private static final int C_64 = 64; private static final int C_64 = 64;
/** /**
* Minimum precision after discarding whole 32-bit words from the significand * Minimum precision after discarding whole 32-bit words from the significand
*/ */
private static final int MIN_PRECISION = 72; private static final int MIN_PRECISION = 72;
private BigInteger _significand; private BigInteger _significand;
private int _binaryExponent; private int _binaryExponent;
public MutableFPNumber(BigInteger frac, int binaryExponent) { public MutableFPNumber(BigInteger frac, int binaryExponent) {
_significand = frac; _significand = frac;
_binaryExponent = binaryExponent; _binaryExponent = binaryExponent;
} }
public MutableFPNumber copy() { public MutableFPNumber copy() {
return new MutableFPNumber(_significand, _binaryExponent); return new MutableFPNumber(_significand, _binaryExponent);
} }
public void normalise64bit() { public void normalise64bit() {
int oldBitLen = _significand.bitLength(); int oldBitLen = _significand.bitLength();
int sc = oldBitLen - C_64; int sc = oldBitLen - C_64;
if (sc == 0) { if (sc == 0) {
return; return;
} }
if (sc < 0) { if (sc < 0) {
throw new IllegalStateException("Not enough precision"); throw new IllegalStateException("Not enough precision");
} }
_binaryExponent += sc; _binaryExponent += sc;
if (sc > 32) { if (sc > 32) {
int highShift = (sc-1) & 0xFFFFE0; int highShift = (sc-1) & 0xFFFFE0;
_significand = _significand.shiftRight(highShift); _significand = _significand.shiftRight(highShift);
sc -= highShift; sc -= highShift;
oldBitLen -= highShift; oldBitLen -= highShift;
} }
if (sc < 1) { if (sc < 1) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
_significand = Rounder.round(_significand, sc); _significand = Rounder.round(_significand, sc);
if (_significand.bitLength() > oldBitLen) { if (_significand.bitLength() > oldBitLen) {
sc++; sc++;
_binaryExponent++; _binaryExponent++;
} }
_significand = _significand.shiftRight(sc); _significand = _significand.shiftRight(sc);
} }
public int get64BitNormalisedExponent() { public int get64BitNormalisedExponent() {
return _binaryExponent + _significand.bitLength() - C_64; return _binaryExponent + _significand.bitLength() - C_64;
} }
@Override public boolean isBelowMaxRep() {
public boolean equals(Object obj) { int sc = _significand.bitLength() - C_64;
MutableFPNumber other = (MutableFPNumber) obj; return _significand.compareTo(BI_MAX_BASE.shiftLeft(sc)) < 0;
if (_binaryExponent != other._binaryExponent) { }
return false; public boolean isAboveMinRep() {
} int sc = _significand.bitLength() - C_64;
return _significand.equals(other._significand); return _significand.compareTo(BI_MIN_BASE.shiftLeft(sc)) > 0;
} }
public boolean isBelowMaxRep() { public NormalisedDecimal createNormalisedDecimal(int pow10) {
int sc = _significand.bitLength() - C_64; // missingUnderBits is (0..3)
return _significand.compareTo(BI_MAX_BASE.shiftLeft(sc)) < 0; int missingUnderBits = _binaryExponent-39;
} int fracPart = (_significand.intValue() << missingUnderBits) & 0xFFFF80;
public boolean isAboveMinRep() { long wholePart = _significand.shiftRight(C_64-_binaryExponent-1).longValue();
int sc = _significand.bitLength() - C_64; return new NormalisedDecimal(wholePart, fracPart, pow10);
return _significand.compareTo(BI_MIN_BASE.shiftLeft(sc)) > 0; }
} public void multiplyByPowerOfTen(int pow10) {
public NormalisedDecimal createNormalisedDecimal(int pow10) { TenPower tp = TenPower.getInstance(Math.abs(pow10));
// missingUnderBits is (0..3) if (pow10 < 0) {
int missingUnderBits = _binaryExponent-39; mulShift(tp._divisor, tp._divisorShift);
int fracPart = (_significand.intValue() << missingUnderBits) & 0xFFFF80; } else {
long wholePart = _significand.shiftRight(C_64-_binaryExponent-1).longValue(); mulShift(tp._multiplicand, tp._multiplierShift);
return new NormalisedDecimal(wholePart, fracPart, pow10); }
} }
public void multiplyByPowerOfTen(int pow10) { private void mulShift(BigInteger multiplicand, int multiplierShift) {
TenPower tp = TenPower.getInstance(Math.abs(pow10)); _significand = _significand.multiply(multiplicand);
if (pow10 < 0) { _binaryExponent += multiplierShift;
mulShift(tp._divisor, tp._divisorShift); // check for too much precision
} else { int sc = (_significand.bitLength() - MIN_PRECISION) & 0xFFFFFFE0;
mulShift(tp._multiplicand, tp._multiplierShift); // 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
private void mulShift(BigInteger multiplicand, int multiplierShift) { _significand = _significand.shiftRight(sc);
_significand = _significand.multiply(multiplicand); _binaryExponent += sc;
_binaryExponent += multiplierShift; }
// check for too much precision }
int sc = (_significand.bitLength() - MIN_PRECISION) & 0xFFFFFFE0;
// mask makes multiples of 32 which optimises BigInteger.shiftRight private static final class Rounder {
if (sc > 0) { private static final BigInteger[] HALF_BITS;
// no need to round because we have at least 8 bits of extra precision
_significand = _significand.shiftRight(sc); static {
_binaryExponent += sc; BigInteger[] bis = new BigInteger[33];
} long acc=1;
} for (int i = 1; i < bis.length; i++) {
bis[i] = BigInteger.valueOf(acc);
private static final class Rounder { acc <<=1;
private static final BigInteger[] HALF_BITS; }
HALF_BITS = bis;
static { }
BigInteger[] bis = new BigInteger[33]; /**
long acc=1; * @param nBits number of bits to shift right
for (int i = 1; i < bis.length; i++) { */
bis[i] = BigInteger.valueOf(acc); public static BigInteger round(BigInteger bi, int nBits) {
acc <<=1; if (nBits < 1) {
} return bi;
HALF_BITS = bis; }
} return bi.add(HALF_BITS[nBits]);
/** }
* @param nBits number of bits to shift right }
*/
public static BigInteger round(BigInteger bi, int nBits) { /**
if (nBits < 1) { * Holds values for quick multiplication and division by 10
return bi; */
} private static final class TenPower {
return bi.add(HALF_BITS[nBits]); private static final BigInteger FIVE = new BigInteger("5");
} private static final TenPower[] _cache = new TenPower[350];
}
public final BigInteger _multiplicand;
/** public final BigInteger _divisor;
* Holds values for quick multiplication and division by 10 public final int _divisorShift;
*/ public final int _multiplierShift;
private static final class TenPower {
private static final BigInteger FIVE = new BigInteger("5"); private TenPower(int index) {
private static final TenPower[] _cache = new TenPower[350]; BigInteger fivePowIndex = FIVE.pow(index);
public final BigInteger _multiplicand; int bitsDueToFiveFactors = fivePowIndex.bitLength();
public final BigInteger _divisor; int px = 80 + bitsDueToFiveFactors;
public final int _divisorShift; BigInteger fx = BigInteger.ONE.shiftLeft(px).divide(fivePowIndex);
public final int _multiplierShift; int adj = fx.bitLength() - 80;
_divisor = fx.shiftRight(adj);
private TenPower(int index) { bitsDueToFiveFactors -= adj;
BigInteger fivePowIndex = FIVE.pow(index);
_divisorShift = -(bitsDueToFiveFactors+index+80);
int bitsDueToFiveFactors = fivePowIndex.bitLength(); int sc = fivePowIndex.bitLength() - 68;
int px = 80 + bitsDueToFiveFactors; if (sc > 0) {
BigInteger fx = BigInteger.ONE.shiftLeft(px).divide(fivePowIndex); _multiplierShift = index + sc;
int adj = fx.bitLength() - 80; _multiplicand = fivePowIndex.shiftRight(sc);
_divisor = fx.shiftRight(adj); } else {
bitsDueToFiveFactors -= adj; _multiplierShift = index;
_multiplicand = fivePowIndex;
_divisorShift = -(bitsDueToFiveFactors+index+80); }
int sc = fivePowIndex.bitLength() - 68; }
if (sc > 0) {
_multiplierShift = index + sc; static TenPower getInstance(int index) {
_multiplicand = fivePowIndex.shiftRight(sc); TenPower result = _cache[index];
} else { if (result == null) {
_multiplierShift = index; result = new TenPower(index);
_multiplicand = fivePowIndex; _cache[index] = result;
} }
} return result;
}
static TenPower getInstance(int index) { }
TenPower result = _cache[index];
if (result == null) { public ExpandedDouble createExpandedDouble() {
result = new TenPower(index); return new ExpandedDouble(_significand, _binaryExponent);
_cache[index] = result; }
} }
return result;
}
}
public ExpandedDouble createExpandedDouble() {
return new ExpandedDouble(_significand, _binaryExponent);
}
}