ICU-13060 Assorted FindBugs fixes for DecimalFormat. Moving old implementation to core-tests project.
X-SVN-Rev: 39923
This commit is contained in:
parent
af55f69558
commit
3d1d6e5103
@ -40,7 +40,7 @@ public abstract class Format {
|
||||
int length = process(inputDeque, modDeque, sb, 0);
|
||||
|
||||
// Resolve remaining affixes
|
||||
length += modDeque.applyAll(sb, 0, length);
|
||||
modDeque.applyAll(sb, 0, length);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ public abstract class Format {
|
||||
ModifierHolder mods = threadLocalModifierHolder.get().clear();
|
||||
NumberStringBuilder sb = threadLocalStringBuilder.get().clear();
|
||||
int length = process(input, mods, sb, 0);
|
||||
length += mods.applyAll(sb, 0, length);
|
||||
mods.applyAll(sb, 0, length);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,12 @@ public interface FormatQuantity extends PluralRules.IFixedDecimal {
|
||||
*/
|
||||
public int getLowerDisplayMagnitude();
|
||||
|
||||
public FormatQuantity clone();
|
||||
/**
|
||||
* Like clone, but without the restrictions of the Cloneable interface clone.
|
||||
*
|
||||
* @return A copy of this instance which can be mutated without affecting this instance.
|
||||
*/
|
||||
public FormatQuantity createCopy();
|
||||
|
||||
public void copyFrom(FormatQuantity other);
|
||||
|
||||
|
@ -247,7 +247,7 @@ public class FormatQuantity1 implements FormatQuantity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormatQuantity clone() {
|
||||
public FormatQuantity1 createCopy() {
|
||||
return new FormatQuantity1(this);
|
||||
}
|
||||
|
||||
@ -675,7 +675,7 @@ public class FormatQuantity1 implements FormatQuantity {
|
||||
|
||||
private int fractionCount() {
|
||||
// TODO: This is temporary.
|
||||
FormatQuantity1 copy = (FormatQuantity1) this.clone();
|
||||
FormatQuantity1 copy = new FormatQuantity1(this);
|
||||
int fractionCount = 0;
|
||||
while (copy.hasNextFraction()) {
|
||||
copy.nextFraction();
|
||||
@ -707,7 +707,7 @@ public class FormatQuantity1 implements FormatQuantity {
|
||||
@Override
|
||||
public byte getDigit(int magnitude) {
|
||||
// TODO: This is temporary.
|
||||
FormatQuantity1 copy = (FormatQuantity1) this.clone();
|
||||
FormatQuantity1 copy = new FormatQuantity1(this);
|
||||
if (magnitude < 0) {
|
||||
for (int p = -1; p > magnitude; p--) {
|
||||
copy.nextFraction();
|
||||
|
@ -18,7 +18,7 @@ public final class FormatQuantity4 extends FormatQuantityBCD {
|
||||
|
||||
private long bcdLong = 0L;
|
||||
|
||||
private boolean usingBytes = false;;
|
||||
private boolean usingBytes = false;
|
||||
|
||||
@Override
|
||||
public int maxRepresentableDigits() {
|
||||
@ -281,7 +281,8 @@ public final class FormatQuantity4 extends FormatQuantityBCD {
|
||||
}
|
||||
|
||||
private void ensureCapacity(int capacity) {
|
||||
if (bcdBytes == null && capacity > 0) {
|
||||
if (capacity == 0) return;
|
||||
if (bcdBytes == null) {
|
||||
bcdBytes = new byte[capacity];
|
||||
} else if (bcdBytes.length < capacity) {
|
||||
byte[] bcd1 = new byte[capacity * 2];
|
||||
|
@ -50,13 +50,30 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
protected static final int INFINITY_FLAG = 2;
|
||||
protected static final int NAN_FLAG = 4;
|
||||
|
||||
// The following three fields relate to the double-to-ascii fast path algorithm.
|
||||
// When a double is given to FormatQuantityBCD, it is converted to using a fast algorithm. The
|
||||
// fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
|
||||
// of rounding the number ensures that the converted digits are correct, falling back to a slow-
|
||||
// path algorithm if required. Therefore, if a FormatQuantity is constructed from a double, it
|
||||
// is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
|
||||
// you don't round, assertions will fail in certain other methods if you try calling them.
|
||||
|
||||
/**
|
||||
* The original number provided by the user and which is represented in BCD. Used when we need to
|
||||
* re-compute the BCD for an exact double representation.
|
||||
*/
|
||||
protected double origDouble;
|
||||
|
||||
/**
|
||||
* The change in magnitude relative to the original double. Used when we need to re-compute the
|
||||
* BCD for an exact double representation.
|
||||
*/
|
||||
protected int origDelta;
|
||||
|
||||
/**
|
||||
* Whether the value in the BCD comes from the double fast path without having been rounded to
|
||||
* ensure correctness
|
||||
*/
|
||||
protected boolean isApproximate;
|
||||
|
||||
// Four positions: left optional '(', left required '[', right required ']', right optional ')'.
|
||||
@ -209,6 +226,10 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
|
||||
@Override
|
||||
public double getPluralOperand(Operand operand) {
|
||||
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
|
||||
// See the comment at the top of this file explaining the "isApproximate" field.
|
||||
assert !isApproximate;
|
||||
|
||||
switch (operand) {
|
||||
case i:
|
||||
return toLong();
|
||||
@ -241,6 +262,10 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
|
||||
@Override
|
||||
public int getUpperDisplayMagnitude() {
|
||||
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
|
||||
// See the comment at the top of this file explaining the "isApproximate" field.
|
||||
assert !isApproximate;
|
||||
|
||||
int magnitude = scale + precision;
|
||||
int result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude;
|
||||
return result - 1;
|
||||
@ -248,6 +273,10 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
|
||||
@Override
|
||||
public int getLowerDisplayMagnitude() {
|
||||
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
|
||||
// See the comment at the top of this file explaining the "isApproximate" field.
|
||||
assert !isApproximate;
|
||||
|
||||
int magnitude = scale;
|
||||
int result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude;
|
||||
return result;
|
||||
@ -255,6 +284,10 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
|
||||
@Override
|
||||
public byte getDigit(int magnitude) {
|
||||
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
|
||||
// See the comment at the top of this file explaining the "isApproximate" field.
|
||||
assert !isApproximate;
|
||||
|
||||
return getDigitPos(magnitude - scale);
|
||||
}
|
||||
|
||||
@ -287,7 +320,7 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormatQuantity clone() {
|
||||
public FormatQuantity createCopy() {
|
||||
if (this instanceof FormatQuantity2) {
|
||||
return new FormatQuantity2((FormatQuantity2) this);
|
||||
} else if (this instanceof FormatQuantity3) {
|
||||
@ -295,7 +328,7 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
} else if (this instanceof FormatQuantity4) {
|
||||
return new FormatQuantity4((FormatQuantity4) this);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to clone " + this.getClass());
|
||||
throw new IllegalArgumentException("Don't know how to copy " + this.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,13 +418,6 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
|
||||
flags |= INFINITY_FLAG;
|
||||
} else if (n != 0) {
|
||||
_setToDoubleFast(n);
|
||||
|
||||
// TODO: Remove this when finished testing.
|
||||
// isApproximate = true;
|
||||
// origDouble = n;
|
||||
// origDelta = 0;
|
||||
// convertToAccurateDouble();
|
||||
|
||||
compact();
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,14 @@ public class NumberStringBuilder implements CharSequence {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
public NumberStringBuilder(NumberStringBuilder source) {
|
||||
this(source.chars.length);
|
||||
zero = source.zero;
|
||||
length = source.length;
|
||||
System.arraycopy(source.chars, zero, chars, zero, length);
|
||||
System.arraycopy(source.fields, zero, fields, zero, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return length;
|
||||
@ -155,7 +163,9 @@ public class NumberStringBuilder implements CharSequence {
|
||||
* NumberStringBuilder}.
|
||||
*/
|
||||
public int insert(int index, NumberStringBuilder other) {
|
||||
assert this != other;
|
||||
if (this == other) {
|
||||
throw new IllegalArgumentException("Cannot call insert/append on myself");
|
||||
}
|
||||
int count = other.length;
|
||||
if (count == 0) return 0; // nothing to insert
|
||||
int position = prepareForInsert(index, count);
|
||||
@ -220,7 +230,7 @@ public class NumberStringBuilder implements CharSequence {
|
||||
if (start < 0 || end > length || end < start) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
NumberStringBuilder other = this.clone();
|
||||
NumberStringBuilder other = new NumberStringBuilder(this);
|
||||
other.zero = zero + start;
|
||||
other.length = end - start;
|
||||
return other;
|
||||
@ -393,16 +403,6 @@ public class NumberStringBuilder implements CharSequence {
|
||||
return as.getIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberStringBuilder clone() {
|
||||
NumberStringBuilder other = new NumberStringBuilder(chars.length);
|
||||
other.zero = zero;
|
||||
other.length = length;
|
||||
System.arraycopy(chars, zero, other.chars, zero, length);
|
||||
System.arraycopy(fields, zero, other.fields, zero, length);
|
||||
return other;
|
||||
}
|
||||
|
||||
public NumberStringBuilder clear() {
|
||||
zero = chars.length / 2;
|
||||
length = 0;
|
||||
|
@ -620,6 +620,7 @@ public class Parse {
|
||||
// TODO(sffc): Remove this field if it is not necessary.
|
||||
@SuppressWarnings("unused")
|
||||
SeparatorType groupingType2;
|
||||
|
||||
TextTrieMap<Byte> digitTrie;
|
||||
Set<AffixHolder> affixHolders = new HashSet<AffixHolder>();
|
||||
|
||||
@ -824,14 +825,15 @@ public class Parse {
|
||||
new ConcurrentHashMap<ULocale, CurrencyAffixPatterns>();
|
||||
|
||||
static void addToState(ULocale uloc, ParserState state) {
|
||||
if (!currencyAffixPatterns.containsKey(uloc)) {
|
||||
CurrencyAffixPatterns value = currencyAffixPatterns.get(uloc);
|
||||
if (value == null) {
|
||||
// There can be multiple threads computing the same CurrencyAffixPatterns simultaneously,
|
||||
// but that scenario is harmless.
|
||||
CurrencyAffixPatterns value = new CurrencyAffixPatterns(uloc);
|
||||
currencyAffixPatterns.put(uloc, value);
|
||||
CurrencyAffixPatterns newValue = new CurrencyAffixPatterns(uloc);
|
||||
currencyAffixPatterns.putIfAbsent(uloc, newValue);
|
||||
value = currencyAffixPatterns.get(uloc);
|
||||
}
|
||||
CurrencyAffixPatterns instance = currencyAffixPatterns.get(uloc);
|
||||
state.affixHolders.addAll(instance.set);
|
||||
state.affixHolders.addAll(value.set);
|
||||
}
|
||||
|
||||
private CurrencyAffixPatterns(ULocale uloc) {
|
||||
|
@ -780,7 +780,7 @@ public class PatternString {
|
||||
result.totalIntegerDigits += 1;
|
||||
result.minimumIntegerDigits += 1;
|
||||
// no change to result.minimumSignificantDigits
|
||||
result.maximumSignificantDigits += (seenSignificantDigitMarker ? 1 : 0);
|
||||
// no change to result.maximumSignificantDigits
|
||||
result.rounding.appendDigit((byte) (state.peek() - '0'), 0, true);
|
||||
break;
|
||||
|
||||
|
@ -201,7 +201,8 @@ public abstract class Rounder extends Format.BeforeFormat {
|
||||
* @return The multiplier that was chosen to best fit the input.
|
||||
*/
|
||||
public int chooseMultiplierAndApply(FormatQuantity input, MultiplierGenerator mg) {
|
||||
FormatQuantity copy = input.clone();
|
||||
// TODO: Avoid the object creation here.
|
||||
FormatQuantity copy = input.createCopy();
|
||||
|
||||
int magnitude = input.getMagnitude();
|
||||
int multiplier = mg.getMultiplier(magnitude);
|
||||
|
@ -1,123 +0,0 @@
|
||||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
|
||||
import com.ibm.icu.impl.number.formatters.RangeFormat;
|
||||
import com.ibm.icu.impl.number.modifiers.SimpleModifier;
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
|
||||
public class demo {
|
||||
|
||||
public static void main(String[] args) throws ParseException {
|
||||
SimpleModifier.testFormatAsPrefixSuffix();
|
||||
|
||||
System.out.println(new FormatQuantity1(3.14159));
|
||||
System.out.println(new FormatQuantity1(3.14159, true));
|
||||
System.out.println(new FormatQuantity2(3.14159));
|
||||
|
||||
System.out.println(
|
||||
PatternString.propertiesToString(PatternString.parseToProperties("+**##,##,#00.05#%")));
|
||||
|
||||
ParsePosition ppos = new ParsePosition(0);
|
||||
System.out.println(
|
||||
Parse.parse(
|
||||
"dd123",
|
||||
ppos,
|
||||
new Properties().setPositivePrefix("dd").setNegativePrefix("ddd"),
|
||||
DecimalFormatSymbols.getInstance()));
|
||||
System.out.println(ppos);
|
||||
|
||||
List<Format> formats = new ArrayList<Format>();
|
||||
|
||||
Properties properties = new Properties();
|
||||
Format ndf = Endpoint.fromBTA(properties);
|
||||
formats.add(ndf);
|
||||
|
||||
properties =
|
||||
new Properties()
|
||||
.setMinimumSignificantDigits(3)
|
||||
.setMaximumSignificantDigits(3)
|
||||
.setCompactStyle(CompactStyle.LONG);
|
||||
Format cdf = Endpoint.fromBTA(properties);
|
||||
formats.add(cdf);
|
||||
|
||||
properties =
|
||||
new Properties().setFormatWidth(10).setPadPosition(PadPosition.AFTER_PREFIX);
|
||||
Format pdf = Endpoint.fromBTA(properties);
|
||||
formats.add(pdf);
|
||||
|
||||
properties =
|
||||
new Properties()
|
||||
.setMinimumExponentDigits(1)
|
||||
.setMaximumIntegerDigits(3)
|
||||
.setMaximumFractionDigits(1);
|
||||
Format exf = Endpoint.fromBTA(properties);
|
||||
formats.add(exf);
|
||||
|
||||
properties = new Properties().setRoundingIncrement(new BigDecimal("0.5"));
|
||||
Format rif = Endpoint.fromBTA(properties);
|
||||
formats.add(rif);
|
||||
|
||||
properties = new Properties().setMeasureUnit(MeasureUnit.HECTARE);
|
||||
Format muf = Endpoint.fromBTA(properties);
|
||||
formats.add(muf);
|
||||
|
||||
properties =
|
||||
new Properties().setMeasureUnit(MeasureUnit.HECTARE).setCompactStyle(CompactStyle.LONG);
|
||||
Format cmf = Endpoint.fromBTA(properties);
|
||||
formats.add(cmf);
|
||||
|
||||
properties = PatternString.parseToProperties("#,##0.00 \u00a4");
|
||||
Format ptf = Endpoint.fromBTA(properties);
|
||||
formats.add(ptf);
|
||||
|
||||
RangeFormat rf = new RangeFormat(cdf, cdf, " to ");
|
||||
System.out.println(rf.format(new FormatQuantity2(1234), new FormatQuantity2(2345)));
|
||||
|
||||
String[] cases = {
|
||||
"1.0",
|
||||
"2.01",
|
||||
"1234.56",
|
||||
"3000.0",
|
||||
// "512.0000000000017",
|
||||
// "4096.000000000001",
|
||||
// "4096.000000000004",
|
||||
// "4096.000000000005",
|
||||
// "4096.000000000006",
|
||||
// "4096.000000000007",
|
||||
"0.00026418",
|
||||
"0.01789261",
|
||||
"468160.0",
|
||||
"999000.0",
|
||||
"999900.0",
|
||||
"999990.0",
|
||||
"0.0",
|
||||
"12345678901.0",
|
||||
// "789000000000000000000000.0",
|
||||
// "789123123567853156372158.0",
|
||||
"-5193.48",
|
||||
};
|
||||
|
||||
for (String str : cases) {
|
||||
System.out.println("----------");
|
||||
System.out.println(str);
|
||||
System.out.println(" NDF: " + ndf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" CDF: " + cdf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" PWD: " + pdf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" EXF: " + exf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" RIF: " + rif.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" MUF: " + muf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" CMF: " + cmf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
System.out.println(" PTF: " + ptf.format(new FormatQuantity2(Double.parseDouble(str))));
|
||||
}
|
||||
}
|
||||
}
|
@ -355,8 +355,8 @@ public class CompactDecimalFormat extends Format.BeforeFormat {
|
||||
@Override
|
||||
public boolean equals(Object _other) {
|
||||
if (_other == null) return false;
|
||||
if (this == _other) return true;
|
||||
CompactDecimalFingerprint other = (CompactDecimalFingerprint) _other;
|
||||
if (this == other) return true;
|
||||
if (compactStyle != other.compactStyle) return false;
|
||||
if (compactType != other.compactType) return false;
|
||||
if (currencySymbol != other.currencySymbol) {
|
||||
|
@ -93,8 +93,6 @@ public class CurrencyFormat {
|
||||
*/
|
||||
@Deprecated
|
||||
public IProperties setCurrencyPluralInfo(CurrencyPluralInfo currencyPluralInfo);
|
||||
|
||||
public IProperties clone();
|
||||
}
|
||||
|
||||
public static interface IProperties
|
||||
|
@ -49,9 +49,6 @@ public class ScientificFormat extends Format.BeforeFormat implements Rounder.Mul
|
||||
* @return The property bag, for chaining.
|
||||
*/
|
||||
public IProperties setMinimumExponentDigits(int minimumExponentDigits);
|
||||
|
||||
@Override
|
||||
public IProperties clone();
|
||||
}
|
||||
|
||||
public static boolean useScientificNotation(IProperties properties) {
|
||||
|
@ -7,7 +7,6 @@ import java.math.RoundingMode;
|
||||
import com.ibm.icu.impl.number.FormatQuantity;
|
||||
import com.ibm.icu.impl.number.Properties;
|
||||
import com.ibm.icu.impl.number.Rounder;
|
||||
import com.ibm.icu.impl.number.Rounder.IBasicRoundingProperties;
|
||||
|
||||
public class SignificantDigitsRounder extends Rounder {
|
||||
|
||||
@ -17,7 +16,7 @@ public class SignificantDigitsRounder extends Rounder {
|
||||
ENSURE_MINIMUM_SIGNIFICANT
|
||||
};
|
||||
|
||||
public static interface IProperties extends IBasicRoundingProperties {
|
||||
public static interface IProperties extends Rounder.IBasicRoundingProperties {
|
||||
|
||||
static int DEFAULT_MINIMUM_SIGNIFICANT_DIGITS = -1;
|
||||
|
||||
|
@ -10,6 +10,8 @@ package com.ibm.icu.text;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
import com.ibm.icu.impl.number.FormatQuantity4;
|
||||
|
||||
//===================================================================
|
||||
// NFSubstitution (abstract base class)
|
||||
//===================================================================
|
||||
@ -232,7 +234,8 @@ abstract class NFSubstitution {
|
||||
* @param that The substitution to compare this one to
|
||||
* @return true if the two substitutions are functionally equivalent
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
// compare class and all of the fields all substitutions have
|
||||
// in common
|
||||
if (that == null) {
|
||||
@ -250,8 +253,9 @@ abstract class NFSubstitution {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
assert false : "hashCode not designed";
|
||||
return 42;
|
||||
}
|
||||
@ -262,7 +266,8 @@ abstract class NFSubstitution {
|
||||
* not be identical to the description it was created from, but
|
||||
* it'll produce the same result.
|
||||
*/
|
||||
public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
// use tokenChar() to get the character at the beginning and
|
||||
// end of the substitution token. In between them will go
|
||||
// either the name of the rule set it uses, or the pattern of
|
||||
@ -586,7 +591,8 @@ class SameValueSubstitution extends NFSubstitution {
|
||||
* Returns "number" unchanged.
|
||||
* @return "number"
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return number;
|
||||
}
|
||||
|
||||
@ -594,7 +600,8 @@ class SameValueSubstitution extends NFSubstitution {
|
||||
* Returns "number" unchanged.
|
||||
* @return "number"
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
return number;
|
||||
}
|
||||
|
||||
@ -611,7 +618,8 @@ class SameValueSubstitution extends NFSubstitution {
|
||||
* substitution.
|
||||
* @return newRuleValue
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return newRuleValue;
|
||||
}
|
||||
|
||||
@ -620,7 +628,8 @@ class SameValueSubstitution extends NFSubstitution {
|
||||
* @param oldUpperBound The current upper bound.
|
||||
* @return oldUpperBound
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return oldUpperBound;
|
||||
}
|
||||
|
||||
@ -632,7 +641,8 @@ class SameValueSubstitution extends NFSubstitution {
|
||||
* The token character for a SameValueSubstitution is =.
|
||||
* @return '='
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '=';
|
||||
}
|
||||
}
|
||||
@ -691,7 +701,8 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* @param radix The radix of the divisor.
|
||||
* @param exponent The exponent of the divisor.
|
||||
*/
|
||||
public void setDivisor(int radix, short exponent) {
|
||||
@Override
|
||||
public void setDivisor(int radix, short exponent) {
|
||||
divisor = NFRule.power(radix, exponent);
|
||||
|
||||
if (divisor == 0) {
|
||||
@ -708,10 +719,11 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* @param that The other substitution
|
||||
* @return true if the two substitutions are functionally equal
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
return super.equals(that) && divisor == ((MultiplierSubstitution) that).divisor;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// formatting
|
||||
//-----------------------------------------------------------------------
|
||||
@ -721,7 +733,8 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted.
|
||||
* @return "number" divided by the rule's divisor
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return (long)Math.floor(number / divisor);
|
||||
}
|
||||
|
||||
@ -734,7 +747,8 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return "number" divided by the rule's divisor
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
if (ruleSet == null) {
|
||||
return number / divisor;
|
||||
} else {
|
||||
@ -755,7 +769,8 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* substitution
|
||||
* @return newRuleValue * divisor
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return newRuleValue * divisor;
|
||||
}
|
||||
|
||||
@ -764,7 +779,8 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* @param oldUpperBound Ignored.
|
||||
* @return The rule's divisor.
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return divisor;
|
||||
}
|
||||
|
||||
@ -776,7 +792,8 @@ class MultiplierSubstitution extends NFSubstitution {
|
||||
* The token character for a multiplier substitution is <.
|
||||
* @return '<'
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '<';
|
||||
}
|
||||
}
|
||||
@ -858,7 +875,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param radix The radix of the divisor.
|
||||
* @param exponent The exponent of the divisor.
|
||||
*/
|
||||
public void setDivisor(int radix, short exponent) {
|
||||
@Override
|
||||
public void setDivisor(int radix, short exponent) {
|
||||
divisor = NFRule.power(radix, exponent);
|
||||
|
||||
if (divisor == 0) { // this will cause recursion
|
||||
@ -876,7 +894,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param that The other substitution
|
||||
* @return true if the two substitutions are functionally equivalent
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (super.equals(that)) {
|
||||
ModulusSubstitution that2 = (ModulusSubstitution)that;
|
||||
|
||||
@ -885,7 +904,7 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// formatting
|
||||
//-----------------------------------------------------------------------
|
||||
@ -898,7 +917,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* into
|
||||
* @param position The position of the rule text in toInsertInto
|
||||
*/
|
||||
public void doSubstitution(long number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
@Override
|
||||
public void doSubstitution(long number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
// if this isn't a >>> substitution, just use the inherited version
|
||||
// of this function (which uses either a rule set or a DecimalFormat
|
||||
// to format its substitution value)
|
||||
@ -921,7 +941,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* into
|
||||
* @param position The position of the rule text in toInsertInto
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
@Override
|
||||
public void doSubstitution(double number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
// if this isn't a >>> substitution, just use the inherited version
|
||||
// of this function (which uses either a rule set or a DecimalFormat
|
||||
// to format its substitution value)
|
||||
@ -943,7 +964,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return "number" mod divisor
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return number % divisor;
|
||||
}
|
||||
|
||||
@ -953,7 +975,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return "number" mod divisor
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
return Math.floor(number % divisor);
|
||||
}
|
||||
|
||||
@ -970,7 +993,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param baseValue The partial parse result prior to calling this
|
||||
* routine.
|
||||
*/
|
||||
public Number doParse(String text, ParsePosition parsePosition, double baseValue,
|
||||
@Override
|
||||
public Number doParse(String text, ParsePosition parsePosition, double baseValue,
|
||||
double upperBound, boolean lenientParse) {
|
||||
// if this isn't a >>> substitution, we can just use the
|
||||
// inherited parse() routine to do the parsing
|
||||
@ -1010,7 +1034,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param oldRuleValue The base value of the rule containing the
|
||||
* substitution
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return (oldRuleValue - (oldRuleValue % divisor)) + newRuleValue;
|
||||
}
|
||||
|
||||
@ -1019,7 +1044,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* @param oldUpperBound Ignored
|
||||
* @return The owning rule's divisor
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return divisor;
|
||||
}
|
||||
|
||||
@ -1031,7 +1057,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* Returns true. This _is_ a ModulusSubstitution.
|
||||
* @return true
|
||||
*/
|
||||
public boolean isModulusSubstitution() {
|
||||
@Override
|
||||
public boolean isModulusSubstitution() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1039,7 +1066,8 @@ class ModulusSubstitution extends NFSubstitution {
|
||||
* The token character of a ModulusSubstitution is >.
|
||||
* @return '>'
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '>';
|
||||
}
|
||||
}
|
||||
@ -1077,7 +1105,8 @@ class IntegralPartSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return "number" unchanged
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return number;
|
||||
}
|
||||
|
||||
@ -1086,7 +1115,8 @@ class IntegralPartSubstitution extends NFSubstitution {
|
||||
* @param number The integral part of the number being formatted
|
||||
* @return floor(number)
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
return Math.floor(number);
|
||||
}
|
||||
|
||||
@ -1104,7 +1134,8 @@ class IntegralPartSubstitution extends NFSubstitution {
|
||||
* calling this function
|
||||
* @return oldRuleValue + newRuleValue
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return newRuleValue + oldRuleValue;
|
||||
}
|
||||
|
||||
@ -1114,7 +1145,8 @@ class IntegralPartSubstitution extends NFSubstitution {
|
||||
* @param oldUpperBound Ignored
|
||||
* @return Double.MAX_VALUE
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
@ -1126,7 +1158,8 @@ class IntegralPartSubstitution extends NFSubstitution {
|
||||
* An IntegralPartSubstitution's token character is <
|
||||
* @return '<'
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '<';
|
||||
}
|
||||
}
|
||||
@ -1193,7 +1226,8 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
* @param position The position of the owning rule's rule text in
|
||||
* toInsertInto
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
@Override
|
||||
public void doSubstitution(double number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
if (!byDigits) {
|
||||
// if we're not in "byDigits" mode, just use the inherited
|
||||
// doSubstitution() routine
|
||||
@ -1207,27 +1241,18 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
// (this is slower, but more accurate, than doing it from the
|
||||
// other end)
|
||||
|
||||
// just print to string and then use that
|
||||
DigitList dl = new DigitList();
|
||||
dl.set(number, 20, true);
|
||||
FormatQuantity4 fq = new FormatQuantity4(number);
|
||||
fq.roundToInfinity(); // ensure doubles are resolved using slow path
|
||||
|
||||
boolean pad = false;
|
||||
while (dl.count > Math.max(0, dl.decimalAt)) {
|
||||
int mag = fq.getLowerDisplayMagnitude();
|
||||
while (mag < 0) {
|
||||
if (pad && useSpaces) {
|
||||
toInsertInto.insert(position + pos, ' ');
|
||||
} else {
|
||||
pad = true;
|
||||
}
|
||||
ruleSet.format(dl.digits[--dl.count] - '0', toInsertInto, position + pos, recursionCount);
|
||||
}
|
||||
while (dl.decimalAt < 0) {
|
||||
if (pad && useSpaces) {
|
||||
toInsertInto.insert(position + pos, ' ');
|
||||
} else {
|
||||
pad = true;
|
||||
}
|
||||
ruleSet.format(0, toInsertInto, position + pos, recursionCount);
|
||||
++dl.decimalAt;
|
||||
ruleSet.format(fq.getDigit(mag++), toInsertInto, position + pos, recursionCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1238,7 +1263,8 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return 0
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1247,7 +1273,8 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted.
|
||||
* @return number - floor(number)
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
return number - Math.floor(number);
|
||||
}
|
||||
|
||||
@ -1271,7 +1298,8 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
* result; otherwise new Long(0). The result is either a Long or
|
||||
* a Double.
|
||||
*/
|
||||
public Number doParse(String text, ParsePosition parsePosition, double baseValue,
|
||||
@Override
|
||||
public Number doParse(String text, ParsePosition parsePosition, double baseValue,
|
||||
double upperBound, boolean lenientParse) {
|
||||
// if we're not in byDigits mode, we can just use the inherited
|
||||
// doParse()
|
||||
@ -1288,7 +1316,8 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
double result;
|
||||
int digit;
|
||||
|
||||
DigitList dl = new DigitList();
|
||||
FormatQuantity4 fq = new FormatQuantity4();
|
||||
int leadingZeros = 0;
|
||||
while (workText.length() > 0 && workPos.getIndex() != 0) {
|
||||
workPos.setIndex(0);
|
||||
digit = ruleSet.parse(workText, workPos, 10).intValue();
|
||||
@ -1300,7 +1329,12 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
}
|
||||
|
||||
if (workPos.getIndex() != 0) {
|
||||
dl.append('0'+digit);
|
||||
if (digit == 0) {
|
||||
leadingZeros++;
|
||||
} else {
|
||||
fq.appendDigit((byte) digit, leadingZeros, false);
|
||||
leadingZeros = 0;
|
||||
}
|
||||
|
||||
parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
|
||||
workText = workText.substring(workPos.getIndex());
|
||||
@ -1310,7 +1344,7 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
}
|
||||
}
|
||||
}
|
||||
result = dl.count == 0 ? 0 : dl.getDouble();
|
||||
result = fq.toDouble();
|
||||
|
||||
result = composeRuleValue(result, baseValue);
|
||||
return new Double(result);
|
||||
@ -1324,14 +1358,16 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
* this function
|
||||
* @return newRuleValue + oldRuleValue
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return newRuleValue + oldRuleValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not used.
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return 0; // this value is ignored
|
||||
}
|
||||
|
||||
@ -1343,7 +1379,8 @@ class FractionalPartSubstitution extends NFSubstitution {
|
||||
* The token character for a FractionalPartSubstitution is >.
|
||||
* @return '>'
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '>';
|
||||
}
|
||||
}
|
||||
@ -1380,7 +1417,8 @@ class AbsoluteValueSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted.
|
||||
* @return abs(number)
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return Math.abs(number);
|
||||
}
|
||||
|
||||
@ -1389,7 +1427,8 @@ class AbsoluteValueSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted.
|
||||
* @return abs(number)
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
return Math.abs(number);
|
||||
}
|
||||
|
||||
@ -1405,7 +1444,8 @@ class AbsoluteValueSubstitution extends NFSubstitution {
|
||||
* this function
|
||||
* @return -newRuleValue
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return -newRuleValue;
|
||||
}
|
||||
|
||||
@ -1414,7 +1454,8 @@ class AbsoluteValueSubstitution extends NFSubstitution {
|
||||
* @param oldUpperBound Ignored.
|
||||
* @return Double.MAX_VALUE
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
@ -1426,7 +1467,8 @@ class AbsoluteValueSubstitution extends NFSubstitution {
|
||||
* The token character for an AbsoluteValueSubstitution is >
|
||||
* @return '>'
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '>';
|
||||
}
|
||||
}
|
||||
@ -1476,13 +1518,13 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
// Rather than keeping a backpointer to the rule, we copy its
|
||||
// base value here
|
||||
this.denominator = denominator;
|
||||
|
||||
|
||||
this.withZeros = description.endsWith("<<");
|
||||
}
|
||||
|
||||
static String fixdesc(String description) {
|
||||
return description.endsWith("<<")
|
||||
? description.substring(0,description.length()-1)
|
||||
return description.endsWith("<<")
|
||||
? description.substring(0,description.length()-1)
|
||||
: description;
|
||||
}
|
||||
|
||||
@ -1495,7 +1537,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* @param that The other NumeratorSubstitution
|
||||
* @return true if the two objects are functionally equivalent
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (super.equals(that)) {
|
||||
NumeratorSubstitution that2 = (NumeratorSubstitution)that;
|
||||
return denominator == that2.denominator && withZeros == that2.withZeros;
|
||||
@ -1503,7 +1546,7 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// formatting
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1518,7 +1561,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* rule text begins (this value is added to this substitution's
|
||||
* position to determine exactly where to insert the new text)
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
@Override
|
||||
public void doSubstitution(double number, StringBuilder toInsertInto, int position, int recursionCount) {
|
||||
// perform a transformation on the number being formatted that
|
||||
// is dependent on the type of substitution this is
|
||||
//String s = toInsertInto.toString();
|
||||
@ -1557,7 +1601,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return number * denominator
|
||||
*/
|
||||
public long transformNumber(long number) {
|
||||
@Override
|
||||
public long transformNumber(long number) {
|
||||
return Math.round(number * denominator);
|
||||
}
|
||||
|
||||
@ -1566,7 +1611,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* @param number The number being formatted
|
||||
* @return number * denominator
|
||||
*/
|
||||
public double transformNumber(double number) {
|
||||
@Override
|
||||
public double transformNumber(double number) {
|
||||
return Math.round(number * denominator);
|
||||
}
|
||||
|
||||
@ -1578,7 +1624,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* Dispatches to the inherited version of this function, but makes
|
||||
* sure that lenientParse is off.
|
||||
*/
|
||||
public Number doParse(String text, ParsePosition parsePosition, double baseValue,
|
||||
@Override
|
||||
public Number doParse(String text, ParsePosition parsePosition, double baseValue,
|
||||
double upperBound, boolean lenientParse) {
|
||||
// we don't have to do anything special to do the parsing here,
|
||||
// but we have to turn lenient parsing off-- if we leave it on,
|
||||
@ -1620,7 +1667,7 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
if (withZeros) {
|
||||
// any base value will do in this case. is there a way to
|
||||
// force this to not bother trying all the base values?
|
||||
|
||||
|
||||
// compute the 'effective' base and prescale the value down
|
||||
long n = result.longValue();
|
||||
long d = 1;
|
||||
@ -1646,7 +1693,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* @param oldRuleValue The owning rule's base value
|
||||
* @return newRuleValue / oldRuleValue
|
||||
*/
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
@Override
|
||||
public double composeRuleValue(double newRuleValue, double oldRuleValue) {
|
||||
return newRuleValue / oldRuleValue;
|
||||
}
|
||||
|
||||
@ -1655,7 +1703,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* @param oldUpperBound Ignored
|
||||
* @return The base value of the rule owning this substitution
|
||||
*/
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
@Override
|
||||
public double calcUpperBound(double oldUpperBound) {
|
||||
return denominator;
|
||||
}
|
||||
|
||||
@ -1667,7 +1716,8 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
* The token character for a NumeratorSubstitution is <
|
||||
* @return '<'
|
||||
*/
|
||||
char tokenChar() {
|
||||
@Override
|
||||
char tokenChar() {
|
||||
return '<';
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
|
||||
private static void testFormatQuantityExpectedOutput(FormatQuantity rq, String expected) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
FormatQuantity q0 = rq.clone();
|
||||
FormatQuantity q0 = rq.createCopy();
|
||||
// Force an accurate double
|
||||
q0.roundToInfinity();
|
||||
q0.setIntegerFractionLength(1, Integer.MAX_VALUE, 1, Integer.MAX_VALUE);
|
||||
@ -181,48 +181,48 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
new MathContext(3, RoundingMode.HALF_UP);
|
||||
|
||||
private static void testFormatQuantityRounding(FormatQuantity rq0, FormatQuantity rq1) {
|
||||
FormatQuantity q0 = rq0.clone();
|
||||
FormatQuantity q1 = rq1.clone();
|
||||
FormatQuantity q0 = rq0.createCopy();
|
||||
FormatQuantity q1 = rq1.createCopy();
|
||||
q0.roundToMagnitude(-1, MATH_CONTEXT_HALF_EVEN);
|
||||
q1.roundToMagnitude(-1, MATH_CONTEXT_HALF_EVEN);
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
|
||||
q0 = rq0.clone();
|
||||
q1 = rq1.clone();
|
||||
q0 = rq0.createCopy();
|
||||
q1 = rq1.createCopy();
|
||||
q0.roundToMagnitude(-1, MATH_CONTEXT_CEILING);
|
||||
q1.roundToMagnitude(-1, MATH_CONTEXT_CEILING);
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
|
||||
q0 = rq0.clone();
|
||||
q1 = rq1.clone();
|
||||
q0 = rq0.createCopy();
|
||||
q1 = rq1.createCopy();
|
||||
q0.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
|
||||
q1.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
}
|
||||
|
||||
private static void testFormatQuantityRoundingInterval(FormatQuantity rq0, FormatQuantity rq1) {
|
||||
FormatQuantity q0 = rq0.clone();
|
||||
FormatQuantity q1 = rq1.clone();
|
||||
FormatQuantity q0 = rq0.createCopy();
|
||||
FormatQuantity q1 = rq1.createCopy();
|
||||
q0.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_HALF_EVEN);
|
||||
q1.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_HALF_EVEN);
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
|
||||
q0 = rq0.clone();
|
||||
q1 = rq1.clone();
|
||||
q0 = rq0.createCopy();
|
||||
q1 = rq1.createCopy();
|
||||
q0.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_CEILING);
|
||||
q1.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_CEILING);
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
}
|
||||
|
||||
private static void testFormatQuantityMath(FormatQuantity rq0, FormatQuantity rq1) {
|
||||
FormatQuantity q0 = rq0.clone();
|
||||
FormatQuantity q1 = rq1.clone();
|
||||
FormatQuantity q0 = rq0.createCopy();
|
||||
FormatQuantity q1 = rq1.createCopy();
|
||||
q0.adjustMagnitude(-3);
|
||||
q1.adjustMagnitude(-3);
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
|
||||
q0 = rq0.clone();
|
||||
q1 = rq1.clone();
|
||||
q0 = rq0.createCopy();
|
||||
q1 = rq1.createCopy();
|
||||
q0.multiplyBy(new BigDecimal("3.14159"));
|
||||
q1.multiplyBy(new BigDecimal("3.14159"));
|
||||
testFormatQuantityBehavior(q0, q1);
|
||||
@ -231,8 +231,8 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
private static void testFormatQuantityWithFormats(
|
||||
FormatQuantity rq0, FormatQuantity rq1, List<Format> formats) {
|
||||
for (Format format : formats) {
|
||||
FormatQuantity q0 = rq0.clone();
|
||||
FormatQuantity q1 = rq1.clone();
|
||||
FormatQuantity q0 = rq0.createCopy();
|
||||
FormatQuantity q1 = rq1.createCopy();
|
||||
String s1 = format.format(q0);
|
||||
String s2 = format.format(q1);
|
||||
assertEquals("Different output from formatter (" + q0 + ", " + q1 + ")", s1, s2);
|
||||
@ -240,8 +240,8 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
}
|
||||
|
||||
private static void testFormatQuantityBehavior(FormatQuantity rq0, FormatQuantity rq1) {
|
||||
FormatQuantity q0 = rq0.clone();
|
||||
FormatQuantity q1 = rq1.clone();
|
||||
FormatQuantity q0 = rq0.createCopy();
|
||||
FormatQuantity q1 = rq1.createCopy();
|
||||
|
||||
assertEquals("Different sign (" + q0 + ", " + q1 + ")", q0.isNegative(), q1.isNegative());
|
||||
|
||||
@ -250,11 +250,6 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
q0.getPositionFingerprint(),
|
||||
q1.getPositionFingerprint());
|
||||
|
||||
assertEquals(
|
||||
"Different upper range of digits (" + q0 + ", " + q1 + ")",
|
||||
q0.getUpperDisplayMagnitude(),
|
||||
q1.getUpperDisplayMagnitude());
|
||||
|
||||
assertDoubleEquals(
|
||||
"Different double values (" + q0 + ", " + q1 + ")", q0.toDouble(), q1.toDouble());
|
||||
|
||||
@ -263,11 +258,19 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
q0.toBigDecimal(),
|
||||
q1.toBigDecimal());
|
||||
|
||||
int equalityDigits = Math.min(q0.maxRepresentableDigits(), q1.maxRepresentableDigits());
|
||||
for (int m = q0.getUpperDisplayMagnitude(), i = 0;
|
||||
m >= Math.min(q0.getLowerDisplayMagnitude(), q1.getLowerDisplayMagnitude())
|
||||
&& i < equalityDigits;
|
||||
m--, i++) {
|
||||
q0.roundToInfinity();
|
||||
q1.roundToInfinity();
|
||||
|
||||
assertEquals(
|
||||
"Different lower display magnitude",
|
||||
q0.getLowerDisplayMagnitude(),
|
||||
q1.getLowerDisplayMagnitude());
|
||||
assertEquals(
|
||||
"Different upper display magnitude",
|
||||
q0.getUpperDisplayMagnitude(),
|
||||
q1.getUpperDisplayMagnitude());
|
||||
|
||||
for (int m = q0.getUpperDisplayMagnitude(); m >= q0.getLowerDisplayMagnitude(); m--) {
|
||||
assertEquals(
|
||||
"Different digit at magnitude " + m + " (" + q0 + ", " + q1 + ")",
|
||||
q0.getDigit(m),
|
||||
@ -341,6 +344,10 @@ public class FormatQuantityTest extends TestFmwk {
|
||||
assertBigDecimalEquals("Failed on append", expected.toString(), fq.toBigDecimal());
|
||||
assertNull("Failed health check", fq.checkHealth());
|
||||
}
|
||||
fq.appendDigit((byte) 9, 2, false);
|
||||
expected.append("009");
|
||||
assertBigDecimalEquals("Failed on append", expected.toString(), fq.toBigDecimal());
|
||||
assertNull("Failed health check", fq.checkHealth());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -114,7 +114,7 @@ public class NumberStringBuilderTest {
|
||||
assertEquals(fields[2], NumberFormat.Field.INTEGER);
|
||||
}
|
||||
|
||||
sb.append(sb.clone());
|
||||
sb.append(new NumberStringBuilder(sb));
|
||||
sb.append(sb.toCharArray(), sb.toFieldArray());
|
||||
int numNull = 0;
|
||||
int numCurr = 0;
|
||||
|
@ -29,6 +29,14 @@ import com.ibm.icu.impl.Utility;
|
||||
import com.ibm.icu.lang.UCharacter;
|
||||
import com.ibm.icu.math.BigDecimal;
|
||||
import com.ibm.icu.math.MathContext;
|
||||
import com.ibm.icu.text.CurrencyPluralInfo;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.text.UFieldPosition;
|
||||
import com.ibm.icu.text.UTF16;
|
||||
import com.ibm.icu.text.UnicodeSet;
|
||||
import com.ibm.icu.text.NumberFormat.Field;
|
||||
import com.ibm.icu.text.PluralRules.FixedDecimal;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
@ -10,6 +10,9 @@ package com.ibm.icu.text;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import com.ibm.icu.text.DecimalFormat;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
|
||||
/**
|
||||
* <code>DigitList</code> handles the transcoding between numeric values and
|
||||
* strings of characters. It only represents non-negative numbers. The
|
||||
@ -43,7 +46,7 @@ import java.math.BigInteger;
|
||||
* @version 1.18 08/12/98
|
||||
* @author Mark Davis, Alan Liu
|
||||
* */
|
||||
final class DigitList {
|
||||
public final class DigitList {
|
||||
/**
|
||||
* The maximum number of significant digits in an IEEE 754 double, that
|
||||
* is, in a Java double. This must not be increased, or garbage digits
|
||||
@ -114,11 +117,11 @@ final class DigitList {
|
||||
ensureCapacity(count+1, count);
|
||||
digits[count++] = (byte) digit;
|
||||
}
|
||||
|
||||
|
||||
public byte getDigitValue(int i) {
|
||||
return (byte) (digits[i] - '0');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility routine to get the value of the digit list
|
||||
* If (count == 0) this throws a NumberFormatException, which
|
||||
@ -203,7 +206,7 @@ final class DigitList {
|
||||
}
|
||||
for (int i = n; i < text.length; ++i) {
|
||||
text[i] = '0';
|
||||
}
|
||||
}
|
||||
return new BigInteger(new String(text));
|
||||
}
|
||||
}
|
||||
@ -253,9 +256,9 @@ final class DigitList {
|
||||
long scale = (long)count - (long)decimalAt;
|
||||
if (scale > 0) {
|
||||
int numDigits = count;
|
||||
if (scale > (long)Integer.MAX_VALUE) {
|
||||
if (scale > Integer.MAX_VALUE) {
|
||||
// try to reduce the scale
|
||||
long numShift = scale - (long)Integer.MAX_VALUE;
|
||||
long numShift = scale - Integer.MAX_VALUE;
|
||||
if (numShift < count) {
|
||||
numDigits -= numShift;
|
||||
} else {
|
||||
@ -529,9 +532,9 @@ final class DigitList {
|
||||
}
|
||||
}
|
||||
|
||||
// Value to indicate that rounding was done.
|
||||
// Value to indicate that rounding was done.
|
||||
private boolean didRound = false;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates if last digit set was rounded or not.
|
||||
* true indicates it was rounded.
|
||||
@ -540,7 +543,7 @@ final class DigitList {
|
||||
public boolean wasRounded() {
|
||||
return didRound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility routine to set the value of the digit list from a long
|
||||
*/
|
||||
@ -567,7 +570,7 @@ final class DigitList {
|
||||
// be represented by DigitList.
|
||||
// [NEW] Faster implementation
|
||||
didRound = false;
|
||||
|
||||
|
||||
if (source <= 0) {
|
||||
if (source == Long.MIN_VALUE) {
|
||||
decimalAt = count = MAX_LONG_DIGITS;
|
||||
@ -580,7 +583,7 @@ final class DigitList {
|
||||
int left = MAX_LONG_DIGITS;
|
||||
int right;
|
||||
while (source > 0) {
|
||||
digits[--left] = (byte) (((long) '0') + (source % 10));
|
||||
digits[--left] = (byte) (('0') + (source % 10));
|
||||
source /= 10;
|
||||
}
|
||||
decimalAt = MAX_LONG_DIGITS-left;
|
||||
@ -590,7 +593,7 @@ final class DigitList {
|
||||
for (right = MAX_LONG_DIGITS - 1; digits[right] == (byte) '0'; --right) {}
|
||||
count = right - left + 1;
|
||||
System.arraycopy(digits, left, digits, 0, count);
|
||||
}
|
||||
}
|
||||
if (maximumDigits > 0) round(maximumDigits);
|
||||
}
|
||||
|
||||
@ -607,7 +610,7 @@ final class DigitList {
|
||||
|
||||
count = decimalAt = stringDigits.length();
|
||||
didRound = false;
|
||||
|
||||
|
||||
// Don't copy trailing zeros
|
||||
while (count > 1 && stringDigits.charAt(count - 1) == '0') --count;
|
||||
|
||||
@ -797,7 +800,8 @@ final class DigitList {
|
||||
/**
|
||||
* equality test between two digit lists.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) // quick check
|
||||
return true;
|
||||
if (!(obj instanceof DigitList)) // (1) same object?
|
||||
@ -815,7 +819,8 @@ final class DigitList {
|
||||
/**
|
||||
* Generates the hash code for the digit list.
|
||||
*/
|
||||
public int hashCode() {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashcode = decimalAt;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
@ -824,7 +829,8 @@ final class DigitList {
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (isZero()) return "0";
|
||||
StringBuilder buf = new StringBuilder("0.");
|
Loading…
Reference in New Issue
Block a user