summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2015-02-17 11:54:28 +0000
committerNarayan Kamath <narayan@google.com>2015-02-17 16:42:55 +0000
commitc10ba1bf470b9ae0d9904e28105de5e679840cb9 (patch)
tree2fb6e858299c3ea8e85c4c9bc26ac6ab6cc79564
parentdb4499e1983c9649c8de7697d10825028fd8094d (diff)
downloadlibcore-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.java8
-rw-r--r--luni/src/main/java/java/text/ChoiceFormat.java78
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 {