ICU-21270 Update FixedDecimal in Java to support exponent

This commit is contained in:
Elango Cheran 2020-09-22 01:19:29 -07:00 committed by Elango
parent f773df26fd
commit 47230019c6
2 changed files with 117 additions and 9 deletions

View file

@ -562,6 +562,8 @@ public class PluralRules implements Serializable {
final boolean isNegative;
final int exponent;
private final int baseFactor;
/**
@ -654,9 +656,10 @@ public class PluralRules implements Serializable {
* @param v number of digits to the right of the decimal place. e.g 1.00 = 2 25. = 0
* @param f Corresponds to f in the plural rules grammar.
* The digits to the right of the decimal place as an integer. e.g 1.10 = 10
* @param e Suppressed exponent for scientific and compact notation
*/
@Deprecated
public FixedDecimal(double n, int v, long f) {
public FixedDecimal(double n, int v, long f, int e) {
isNegative = n < 0;
source = isNegative ? -n : n;
visibleDecimalDigitCount = v;
@ -664,6 +667,7 @@ public class PluralRules implements Serializable {
integerValue = n > MAX
? MAX
: (long)n;
exponent = e;
hasIntegerValue = source == integerValue;
// check values. TODO make into unit test.
//
@ -694,6 +698,24 @@ public class PluralRules implements Serializable {
baseFactor = (int) Math.pow(10, v);
}
/**
* @internal CLDR
* @deprecated This API is ICU internal only.
*/
@Deprecated
public FixedDecimal(double n, int v, long f) {
this(n, v, f, 0);
}
/**
* @internal CLDR
* @deprecated This API is ICU internal only.
*/
@Deprecated
public static FixedDecimal createWithExponent(double n, int v, int e) {
return new FixedDecimal(n,v,getFractionalDigits(n, v), e);
}
/**
* @internal CLDR
* @deprecated This API is ICU internal only.
@ -786,6 +808,29 @@ public class PluralRules implements Serializable {
}
}
/**
* @internal CLDR
* @deprecated This API is ICU internal only
*/
@Deprecated
private FixedDecimal (FixedDecimal other) {
// Ugly, but necessary, because constructors must only call other
// constructors in the first line of the body, and
// FixedDecimal(String) was refactored to support exponents.
this.source = other.source;
this.visibleDecimalDigitCount = other.visibleDecimalDigitCount;
this.visibleDecimalDigitCountWithoutTrailingZeros =
other.visibleDecimalDigitCountWithoutTrailingZeros;
this.decimalDigits = other.decimalDigits;
this.decimalDigitsWithoutTrailingZeros =
other.decimalDigitsWithoutTrailingZeros;
this.integerValue = other.integerValue;
this.hasIntegerValue = other.hasIntegerValue;
this.isNegative = other.isNegative;
this.exponent = other.exponent;
this.baseFactor = other.baseFactor;
}
/**
* @internal CLDR
* @deprecated This API is ICU internal only.
@ -793,7 +838,28 @@ public class PluralRules implements Serializable {
@Deprecated
public FixedDecimal (String n) {
// Ugly, but for samples we don't care.
this(Double.parseDouble(n), getVisibleFractionCount(n));
this(parseDecimalSampleRangeNumString(n));
}
/**
* @internal CLDR
* @deprecated This API is ICU internal only
*/
@Deprecated
private static FixedDecimal parseDecimalSampleRangeNumString(String num) {
if (num.contains("e")) {
int ePos = num.lastIndexOf('e');
int expNumPos = ePos + 1;
String exponentStr = num.substring(expNumPos);
int exponent = Integer.parseInt(exponentStr);
String fractionStr = num.substring(0, ePos);
return FixedDecimal.createWithExponent(
Double.parseDouble(fractionStr),
getVisibleFractionCount(fractionStr),
exponent);
} else {
return new FixedDecimal(Double.parseDouble(num), getVisibleFractionCount(num));
}
}
private static int getVisibleFractionCount(String value) {
@ -822,7 +888,7 @@ public class PluralRules implements Serializable {
case t: return decimalDigitsWithoutTrailingZeros;
case v: return visibleDecimalDigitCount;
case w: return visibleDecimalDigitCountWithoutTrailingZeros;
case e: return 0;
case e: return exponent;
default: return source;
}
}
@ -844,6 +910,9 @@ public class PluralRules implements Serializable {
@Override
@Deprecated
public int compareTo(FixedDecimal other) {
if (exponent != other.exponent) {
return doubleValue() < other.doubleValue() ? -1 : 1;
}
if (integerValue != other.integerValue) {
return integerValue < other.integerValue ? -1 : 1;
}
@ -877,7 +946,8 @@ public class PluralRules implements Serializable {
return false;
}
FixedDecimal other = (FixedDecimal)arg0;
return source == other.source && visibleDecimalDigitCount == other.visibleDecimalDigitCount && decimalDigits == other.decimalDigits;
return source == other.source && visibleDecimalDigitCount == other.visibleDecimalDigitCount && decimalDigits == other.decimalDigits
&& exponent == other.exponent;
}
/**
@ -898,7 +968,12 @@ public class PluralRules implements Serializable {
@Deprecated
@Override
public String toString() {
return String.format(Locale.ROOT, "%." + visibleDecimalDigitCount + "f", source);
String baseString = String.format(Locale.ROOT, "%." + visibleDecimalDigitCount + "f", source);
if (exponent == 0) {
return baseString;
} else {
return baseString + "e" + exponent;
}
}
/**
@ -918,7 +993,7 @@ public class PluralRules implements Serializable {
@Override
public int intValue() {
// TODO Auto-generated method stub
return (int)integerValue;
return (int) longValue();
}
/**
@ -928,7 +1003,11 @@ public class PluralRules implements Serializable {
@Deprecated
@Override
public long longValue() {
return integerValue;
if (exponent == 0) {
return integerValue;
} else {
return (long) (Math.pow(10, exponent) * integerValue);
}
}
/**
@ -938,7 +1017,7 @@ public class PluralRules implements Serializable {
@Deprecated
@Override
public float floatValue() {
return (float) source;
return (float) (source * Math.pow(10, exponent));
}
/**
@ -948,7 +1027,7 @@ public class PluralRules implements Serializable {
@Deprecated
@Override
public double doubleValue() {
return isNegative ? -source : source;
return (isNegative ? -source : source) * Math.pow(10, exponent);
}
/**

View file

@ -190,6 +190,35 @@ public class PluralRulesTest extends TestFmwk {
checkOldSamples(description, test, "other", SampleType.DECIMAL, 99d, 99.1, 99.2d, 999d);
}
/**
* This test is for the support of X.YeZ scientific notation of numbers in
* the plural sample string.
*/
@Test
public void testSamplesWithExponent() {
String description = "one: i = 0,1 @integer 0, 1, 1e5 @decimal 0.0~1.5, 1.1e5; "
+ "many: e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5"
+ " @integer 1000000, 2e6, 3e6, 4e6, 5e6, 6e6, 7e6, … @decimal 2.1e6, 3.1e6, 4.1e6, 5.1e6, 6.1e6, 7.1e6, …; "
+ "other: @integer 2~17, 100, 1000, 10000, 100000, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, …"
+ " @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1e5, 3.1e5, 4.1e5, 5.1e5, 6.1e5, 7.1e5, …"
;
// Creating the PluralRules object means being able to parse numbers
// like 1e5 and 1.1e5
PluralRules test = PluralRules.createRules(description);
checkNewSamples(description, test, "one", PluralRules.SampleType.INTEGER, "@integer 0, 1, 1e5", true,
new FixedDecimal(0));
checkNewSamples(description, test, "one", PluralRules.SampleType.DECIMAL, "@decimal 0.0~1.5, 1.1e5", true,
new FixedDecimal(0, 1));
checkNewSamples(description, test, "many", PluralRules.SampleType.INTEGER, "@integer 1000000, 2e6, 3e6, 4e6, 5e6, 6e6, 7e6, …", false,
new FixedDecimal(1000000));
checkNewSamples(description, test, "many", PluralRules.SampleType.DECIMAL, "@decimal 2.1e6, 3.1e6, 4.1e6, 5.1e6, 6.1e6, 7.1e6, …", false,
FixedDecimal.createWithExponent(2.1, 1, 6));
checkNewSamples(description, test, "other", PluralRules.SampleType.INTEGER, "@integer 2~17, 100, 1000, 10000, 100000, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, …", false,
new FixedDecimal(2));
checkNewSamples(description, test, "other", PluralRules.SampleType.DECIMAL, "@decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1e5, 3.1e5, 4.1e5, 5.1e5, 6.1e5, 7.1e5, …", false,
new FixedDecimal(2.0, 1));
}
public void checkOldSamples(String description, PluralRules rules, String keyword, SampleType sampleType,
Double... expected) {
Collection<Double> oldSamples = rules.getSamples(keyword, sampleType);