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:
parent
af6a4745e2
commit
1833764495
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user