diff options
author | Narayan Kamath <narayan@google.com> | 2015-02-17 11:54:28 +0000 |
---|---|---|
committer | Narayan Kamath <narayan@google.com> | 2015-02-17 16:42:55 +0000 |
commit | c10ba1bf470b9ae0d9904e28105de5e679840cb9 (patch) | |
tree | 2fb6e858299c3ea8e85c4c9bc26ac6ab6cc79564 | |
parent | db4499e1983c9649c8de7697d10825028fd8094d (diff) | |
download | libcore-c10ba1bf470b9ae0d9904e28105de5e679840cb9.zip libcore-c10ba1bf470b9ae0d9904e28105de5e679840cb9.tar.gz libcore-c10ba1bf470b9ae0d9904e28105de5e679840cb9.tar.bz2 |
Handle infinities correctly in ChoiceFormat.
We'd like ChoiceFormat.toPattern to emit a pattern that's parseable
by ChoiceFormat - which means we need an infinity that's parseable by
NumberFormat.parse().
Also, implement the nextDouble / previousDouble public API <sadface/>
in terms of Math.nextAfter and Math.nextUp.
bug: 19149384
Change-Id: Ieb13ee70c212d188ff9fde09463ced8d632f47ab
-rw-r--r-- | harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java | 8 | ||||
-rw-r--r-- | luni/src/main/java/java/text/ChoiceFormat.java | 78 |
2 files changed, 40 insertions, 46 deletions
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java index e4d6bd8..63232ae 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java @@ -466,4 +466,12 @@ public class ChoiceFormatTest extends TestCase { assertEquals("GREATER_THAN_ONE", fmt.format(999999999D)); assertEquals("GREATER_THAN_ONE", fmt.format(Double.POSITIVE_INFINITY)); } + + // http://b/19149384 + public void testToPatternWithInfinities() { + final ChoiceFormat fmt = new ChoiceFormat( + "-\u221E<are negative|0<are fractions|1#is one|1.0<is 1+|\u221E<are many."); + assertEquals("-\u221E<are negative|0.0<are fractions|1.0#is one|1.0<is 1+|\u221E<are many.", + fmt.toPattern()); + } } diff --git a/luni/src/main/java/java/text/ChoiceFormat.java b/luni/src/main/java/java/text/ChoiceFormat.java index 014b8c7..3d3cb3a 100644 --- a/luni/src/main/java/java/text/ChoiceFormat.java +++ b/luni/src/main/java/java/text/ChoiceFormat.java @@ -303,37 +303,16 @@ public class ChoiceFormat extends NumberFormat { } /** - * Returns the double value which is closest to the specified double but - * larger. - * - * @param value - * a double value. - * @return the next larger double value. + * Equivalent to {@link Math#nextUp(double)}. */ public static final double nextDouble(double value) { - if (value == Double.POSITIVE_INFINITY) { - return value; - } - long bits; - // Handle -0.0 - if (value == 0) { - bits = 0; - } else { - bits = Double.doubleToLongBits(value); - } - return Double.longBitsToDouble(value < 0 ? bits - 1 : bits + 1); + return Math.nextUp(value); } /** - * Returns the double value which is closest to the specified double but - * either larger or smaller as specified. - * - * @param value - * a double value. - * @param increment - * {@code true} to get the next larger value, {@code false} to - * get the previous smaller value. - * @return the next larger or smaller double value. + * Equivalent to {@link Math#nextUp(double)} if {@code increment == true}, and + * {@link Math#nextAfter(double, double)} with {@code direction == Double.NEGATIVE_INFINITY} + * otherwise. */ public static double nextDouble(double value, boolean increment) { return increment ? nextDouble(value) : previousDouble(value); @@ -385,25 +364,11 @@ public class ChoiceFormat extends NumberFormat { } /** - * Returns the double value which is closest to the specified double but - * smaller. - * - * @param value - * a double value. - * @return the next smaller double value. + * Equivalent to {@link Math#nextAfter(double, double)} with + * {@code direction == Double.NEGATIVE_INFINITY}. */ public static final double previousDouble(double value) { - if (value == Double.NEGATIVE_INFINITY) { - return value; - } - long bits; - // Handle 0.0 - if (value == 0) { - bits = 0x8000000000000000L; - } else { - bits = Double.doubleToLongBits(value); - } - return Double.longBitsToDouble(value <= 0 ? bits + 1 : bits - 1); + return Math.nextAfter(value, Double.NEGATIVE_INFINITY); } /** @@ -453,9 +418,30 @@ public class ChoiceFormat extends NumberFormat { if (i != 0) { buffer.append('|'); } - String previous = String.valueOf(previousDouble(choiceLimits[i])); - String limit = String.valueOf(choiceLimits[i]); - if (previous.length() < limit.length()) { + + final String previous = String.valueOf(previousDouble(choiceLimits[i])); + final String limit = String.valueOf(choiceLimits[i]); + + // Hack to make the output of toPattern parseable by another ChoiceFormat. + // String.valueOf() will emit "Infinity", which isn't parseable by our NumberFormat + // instances. + // + // Ideally, we'd just use NumberFormat.format() to emit output (to be symmetric with + // our usage of NumberFormat.parse()) but it's hard set the right number of significant + // digits in order to output a format string that's equivalent to the original input. + if (Double.isInfinite(choiceLimits[i]) || + Double.isInfinite(previousDouble(choiceLimits[i]))) { + if (choiceLimits[i] < 0) { + buffer.append("-\u221E"); + buffer.append('<'); + } else { + buffer.append('\u221E'); + buffer.append('<'); + } + } else if (previous.length() < limit.length()) { + // What the... i don't even.... sigh. This is trying to figure out whether the + // element was a "<" or a "#". The idea being that users will specify "reasonable" + // quantities and calling nextDouble will result in a "longer" number in most cases. buffer.append(previous); buffer.append('<'); } else { |