1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/text/ChoiceFormat.java Thu Oct 03 15:40:35 2013 +0200
1.3 @@ -0,0 +1,619 @@
1.4 +/*
1.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +/*
1.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
1.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
1.32 + *
1.33 + * The original version of this source code and documentation is copyrighted
1.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
1.35 + * materials are provided under terms of a License Agreement between Taligent
1.36 + * and Sun. This technology is protected by multiple US and International
1.37 + * patents. This notice and attribution to Taligent may not be removed.
1.38 + * Taligent is a registered trademark of Taligent, Inc.
1.39 + *
1.40 + */
1.41 +
1.42 +package java.text;
1.43 +
1.44 +import java.io.InvalidObjectException;
1.45 +import java.io.IOException;
1.46 +import java.io.ObjectInputStream;
1.47 +import java.util.Arrays;
1.48 +
1.49 +/**
1.50 + * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
1.51 + * It is generally used in a <code>MessageFormat</code> for handling plurals.
1.52 + * The choice is specified with an ascending list of doubles, where each item
1.53 + * specifies a half-open interval up to the next item:
1.54 + * <blockquote>
1.55 + * <pre>
1.56 + * X matches j if and only if limit[j] <= X < limit[j+1]
1.57 + * </pre>
1.58 + * </blockquote>
1.59 + * If there is no match, then either the first or last index is used, depending
1.60 + * on whether the number (X) is too low or too high. If the limit array is not
1.61 + * in ascending order, the results of formatting will be incorrect. ChoiceFormat
1.62 + * also accepts <code>\u221E</code> as equivalent to infinity(INF).
1.63 + *
1.64 + * <p>
1.65 + * <strong>Note:</strong>
1.66 + * <code>ChoiceFormat</code> differs from the other <code>Format</code>
1.67 + * classes in that you create a <code>ChoiceFormat</code> object with a
1.68 + * constructor (not with a <code>getInstance</code> style factory
1.69 + * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
1.70 + * doesn't require any complex setup for a given locale. In fact,
1.71 + * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
1.72 + *
1.73 + * <p>
1.74 + * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
1.75 + * and an array of limits. The length of these arrays must be the same.
1.76 + * For example,
1.77 + * <ul>
1.78 + * <li>
1.79 + * <em>limits</em> = {1,2,3,4,5,6,7}<br>
1.80 + * <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
1.81 + * <li>
1.82 + * <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
1.83 + * <em>formats</em> = {"no files", "one file", "many files"}<br>
1.84 + * (<code>nextDouble</code> can be used to get the next higher double, to
1.85 + * make the half-open interval.)
1.86 + * </ul>
1.87 + *
1.88 + * <p>
1.89 + * Here is a simple example that shows formatting and parsing:
1.90 + * <blockquote>
1.91 + * <pre>
1.92 + * double[] limits = {1,2,3,4,5,6,7};
1.93 + * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
1.94 + * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
1.95 + * ParsePosition status = new ParsePosition(0);
1.96 + * for (double i = 0.0; i <= 8.0; ++i) {
1.97 + * status.setIndex(0);
1.98 + * System.out.println(i + " -> " + form.format(i) + " -> "
1.99 + * + form.parse(form.format(i),status));
1.100 + * }
1.101 + * </pre>
1.102 + * </blockquote>
1.103 + * Here is a more complex example, with a pattern format:
1.104 + * <blockquote>
1.105 + * <pre>
1.106 + * double[] filelimits = {0,1,2};
1.107 + * String[] filepart = {"are no files","is one file","are {2} files"};
1.108 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
1.109 + * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
1.110 + * MessageFormat pattform = new MessageFormat("There {0} on {1}");
1.111 + * pattform.setFormats(testFormats);
1.112 + * Object[] testArgs = {null, "ADisk", null};
1.113 + * for (int i = 0; i < 4; ++i) {
1.114 + * testArgs[0] = new Integer(i);
1.115 + * testArgs[2] = testArgs[0];
1.116 + * System.out.println(pattform.format(testArgs));
1.117 + * }
1.118 + * </pre>
1.119 + * </blockquote>
1.120 + * <p>
1.121 + * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
1.122 + * For example:
1.123 + * <blockquote>
1.124 + * <pre>
1.125 + * ChoiceFormat fmt = new ChoiceFormat(
1.126 + * "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
1.127 + * System.out.println("Formatter Pattern : " + fmt.toPattern());
1.128 + *
1.129 + * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
1.130 + * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
1.131 + * System.out.println("Format with 0 : " + fmt.format(0));
1.132 + * System.out.println("Format with 0.9 : " + fmt.format(0.9));
1.133 + * System.out.println("Format with 1.0 : " + fmt.format(1));
1.134 + * System.out.println("Format with 1.5 : " + fmt.format(1.5));
1.135 + * System.out.println("Format with 2 : " + fmt.format(2));
1.136 + * System.out.println("Format with 2.1 : " + fmt.format(2.1));
1.137 + * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
1.138 + * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
1.139 + * </pre>
1.140 + * </blockquote>
1.141 + * And the output result would be like the following:
1.142 + * <blockquote>
1.143 + * <pre>
1.144 + * Format with -INF : is negative
1.145 + * Format with -1.0 : is negative
1.146 + * Format with 0 : is zero or fraction
1.147 + * Format with 0.9 : is zero or fraction
1.148 + * Format with 1.0 : is one
1.149 + * Format with 1.5 : is 1+
1.150 + * Format with 2 : is two
1.151 + * Format with 2.1 : is more than 2.
1.152 + * Format with NaN : is negative
1.153 + * Format with +INF : is more than 2.
1.154 + * </pre>
1.155 + * </blockquote>
1.156 + *
1.157 + * <h4><a name="synchronization">Synchronization</a></h4>
1.158 + *
1.159 + * <p>
1.160 + * Choice formats are not synchronized.
1.161 + * It is recommended to create separate format instances for each thread.
1.162 + * If multiple threads access a format concurrently, it must be synchronized
1.163 + * externally.
1.164 + *
1.165 + *
1.166 + * @see DecimalFormat
1.167 + * @see MessageFormat
1.168 + * @author Mark Davis
1.169 + */
1.170 +public class ChoiceFormat extends NumberFormat {
1.171 +
1.172 + // Proclaim serial compatibility with 1.1 FCS
1.173 + private static final long serialVersionUID = 1795184449645032964L;
1.174 +
1.175 + /**
1.176 + * Sets the pattern.
1.177 + * @param newPattern See the class description.
1.178 + */
1.179 + public void applyPattern(String newPattern) {
1.180 + StringBuffer[] segments = new StringBuffer[2];
1.181 + for (int i = 0; i < segments.length; ++i) {
1.182 + segments[i] = new StringBuffer();
1.183 + }
1.184 + double[] newChoiceLimits = new double[30];
1.185 + String[] newChoiceFormats = new String[30];
1.186 + int count = 0;
1.187 + int part = 0;
1.188 + double startValue = 0;
1.189 + double oldStartValue = Double.NaN;
1.190 + boolean inQuote = false;
1.191 + for (int i = 0; i < newPattern.length(); ++i) {
1.192 + char ch = newPattern.charAt(i);
1.193 + if (ch=='\'') {
1.194 + // Check for "''" indicating a literal quote
1.195 + if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
1.196 + segments[part].append(ch);
1.197 + ++i;
1.198 + } else {
1.199 + inQuote = !inQuote;
1.200 + }
1.201 + } else if (inQuote) {
1.202 + segments[part].append(ch);
1.203 + } else if (ch == '<' || ch == '#' || ch == '\u2264') {
1.204 + if (segments[0].length() == 0) {
1.205 + throw new IllegalArgumentException();
1.206 + }
1.207 + try {
1.208 + String tempBuffer = segments[0].toString();
1.209 + if (tempBuffer.equals("\u221E")) {
1.210 + startValue = Double.POSITIVE_INFINITY;
1.211 + } else if (tempBuffer.equals("-\u221E")) {
1.212 + startValue = Double.NEGATIVE_INFINITY;
1.213 + } else {
1.214 + startValue = Double.valueOf(segments[0].toString()).doubleValue();
1.215 + }
1.216 + } catch (Exception e) {
1.217 + throw new IllegalArgumentException();
1.218 + }
1.219 + if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
1.220 + startValue != Double.NEGATIVE_INFINITY) {
1.221 + startValue = nextDouble(startValue);
1.222 + }
1.223 + if (startValue <= oldStartValue) {
1.224 + throw new IllegalArgumentException();
1.225 + }
1.226 + segments[0].setLength(0);
1.227 + part = 1;
1.228 + } else if (ch == '|') {
1.229 + if (count == newChoiceLimits.length) {
1.230 + newChoiceLimits = doubleArraySize(newChoiceLimits);
1.231 + newChoiceFormats = doubleArraySize(newChoiceFormats);
1.232 + }
1.233 + newChoiceLimits[count] = startValue;
1.234 + newChoiceFormats[count] = segments[1].toString();
1.235 + ++count;
1.236 + oldStartValue = startValue;
1.237 + segments[1].setLength(0);
1.238 + part = 0;
1.239 + } else {
1.240 + segments[part].append(ch);
1.241 + }
1.242 + }
1.243 + // clean up last one
1.244 + if (part == 1) {
1.245 + if (count == newChoiceLimits.length) {
1.246 + newChoiceLimits = doubleArraySize(newChoiceLimits);
1.247 + newChoiceFormats = doubleArraySize(newChoiceFormats);
1.248 + }
1.249 + newChoiceLimits[count] = startValue;
1.250 + newChoiceFormats[count] = segments[1].toString();
1.251 + ++count;
1.252 + }
1.253 + choiceLimits = new double[count];
1.254 + System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
1.255 + choiceFormats = new String[count];
1.256 + System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
1.257 + }
1.258 +
1.259 + /**
1.260 + * Gets the pattern.
1.261 + */
1.262 + public String toPattern() {
1.263 + StringBuffer result = new StringBuffer();
1.264 + for (int i = 0; i < choiceLimits.length; ++i) {
1.265 + if (i != 0) {
1.266 + result.append('|');
1.267 + }
1.268 + // choose based upon which has less precision
1.269 + // approximate that by choosing the closest one to an integer.
1.270 + // could do better, but it's not worth it.
1.271 + double less = previousDouble(choiceLimits[i]);
1.272 + double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
1.273 + double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
1.274 +
1.275 + if (tryLessOrEqual < tryLess) {
1.276 + result.append(""+choiceLimits[i]);
1.277 + result.append('#');
1.278 + } else {
1.279 + if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
1.280 + result.append("\u221E");
1.281 + } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
1.282 + result.append("-\u221E");
1.283 + } else {
1.284 + result.append(""+less);
1.285 + }
1.286 + result.append('<');
1.287 + }
1.288 + // Append choiceFormats[i], using quotes if there are special characters.
1.289 + // Single quotes themselves must be escaped in either case.
1.290 + String text = choiceFormats[i];
1.291 + boolean needQuote = text.indexOf('<') >= 0
1.292 + || text.indexOf('#') >= 0
1.293 + || text.indexOf('\u2264') >= 0
1.294 + || text.indexOf('|') >= 0;
1.295 + if (needQuote) result.append('\'');
1.296 + if (text.indexOf('\'') < 0) result.append(text);
1.297 + else {
1.298 + for (int j=0; j<text.length(); ++j) {
1.299 + char c = text.charAt(j);
1.300 + result.append(c);
1.301 + if (c == '\'') result.append(c);
1.302 + }
1.303 + }
1.304 + if (needQuote) result.append('\'');
1.305 + }
1.306 + return result.toString();
1.307 + }
1.308 +
1.309 + /**
1.310 + * Constructs with limits and corresponding formats based on the pattern.
1.311 + * @see #applyPattern
1.312 + */
1.313 + public ChoiceFormat(String newPattern) {
1.314 + applyPattern(newPattern);
1.315 + }
1.316 +
1.317 + /**
1.318 + * Constructs with the limits and the corresponding formats.
1.319 + * @see #setChoices
1.320 + */
1.321 + public ChoiceFormat(double[] limits, String[] formats) {
1.322 + setChoices(limits, formats);
1.323 + }
1.324 +
1.325 + /**
1.326 + * Set the choices to be used in formatting.
1.327 + * @param limits contains the top value that you want
1.328 + * parsed with that format,and should be in ascending sorted order. When
1.329 + * formatting X, the choice will be the i, where
1.330 + * limit[i] <= X < limit[i+1].
1.331 + * If the limit array is not in ascending order, the results of formatting
1.332 + * will be incorrect.
1.333 + * @param formats are the formats you want to use for each limit.
1.334 + * They can be either Format objects or Strings.
1.335 + * When formatting with object Y,
1.336 + * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
1.337 + * is called. Otherwise Y.toString() is called.
1.338 + */
1.339 + public void setChoices(double[] limits, String formats[]) {
1.340 + if (limits.length != formats.length) {
1.341 + throw new IllegalArgumentException(
1.342 + "Array and limit arrays must be of the same length.");
1.343 + }
1.344 + choiceLimits = limits;
1.345 + choiceFormats = formats;
1.346 + }
1.347 +
1.348 + /**
1.349 + * Get the limits passed in the constructor.
1.350 + * @return the limits.
1.351 + */
1.352 + public double[] getLimits() {
1.353 + return choiceLimits;
1.354 + }
1.355 +
1.356 + /**
1.357 + * Get the formats passed in the constructor.
1.358 + * @return the formats.
1.359 + */
1.360 + public Object[] getFormats() {
1.361 + return choiceFormats;
1.362 + }
1.363 +
1.364 + // Overrides
1.365 +
1.366 + /**
1.367 + * Specialization of format. This method really calls
1.368 + * <code>format(double, StringBuffer, FieldPosition)</code>
1.369 + * thus the range of longs that are supported is only equal to
1.370 + * the range that can be stored by double. This will never be
1.371 + * a practical limitation.
1.372 + */
1.373 + public StringBuffer format(long number, StringBuffer toAppendTo,
1.374 + FieldPosition status) {
1.375 + return format((double)number, toAppendTo, status);
1.376 + }
1.377 +
1.378 + /**
1.379 + * Returns pattern with formatted double.
1.380 + * @param number number to be formatted & substituted.
1.381 + * @param toAppendTo where text is appended.
1.382 + * @param status ignore no useful status is returned.
1.383 + */
1.384 + public StringBuffer format(double number, StringBuffer toAppendTo,
1.385 + FieldPosition status) {
1.386 + // find the number
1.387 + int i;
1.388 + for (i = 0; i < choiceLimits.length; ++i) {
1.389 + if (!(number >= choiceLimits[i])) {
1.390 + // same as number < choiceLimits, except catchs NaN
1.391 + break;
1.392 + }
1.393 + }
1.394 + --i;
1.395 + if (i < 0) i = 0;
1.396 + // return either a formatted number, or a string
1.397 + return toAppendTo.append(choiceFormats[i]);
1.398 + }
1.399 +
1.400 + /**
1.401 + * Parses a Number from the input text.
1.402 + * @param text the source text.
1.403 + * @param status an input-output parameter. On input, the
1.404 + * status.index field indicates the first character of the
1.405 + * source text that should be parsed. On exit, if no error
1.406 + * occured, status.index is set to the first unparsed character
1.407 + * in the source text. On exit, if an error did occur,
1.408 + * status.index is unchanged and status.errorIndex is set to the
1.409 + * first index of the character that caused the parse to fail.
1.410 + * @return A Number representing the value of the number parsed.
1.411 + */
1.412 + public Number parse(String text, ParsePosition status) {
1.413 + // find the best number (defined as the one with the longest parse)
1.414 + int start = status.index;
1.415 + int furthest = start;
1.416 + double bestNumber = Double.NaN;
1.417 + double tempNumber = 0.0;
1.418 + for (int i = 0; i < choiceFormats.length; ++i) {
1.419 + String tempString = choiceFormats[i];
1.420 + if (text.regionMatches(start, tempString, 0, tempString.length())) {
1.421 + status.index = start + tempString.length();
1.422 + tempNumber = choiceLimits[i];
1.423 + if (status.index > furthest) {
1.424 + furthest = status.index;
1.425 + bestNumber = tempNumber;
1.426 + if (furthest == text.length()) break;
1.427 + }
1.428 + }
1.429 + }
1.430 + status.index = furthest;
1.431 + if (status.index == start) {
1.432 + status.errorIndex = furthest;
1.433 + }
1.434 + return new Double(bestNumber);
1.435 + }
1.436 +
1.437 + /**
1.438 + * Finds the least double greater than d.
1.439 + * If NaN, returns same value.
1.440 + * <p>Used to make half-open intervals.
1.441 + * @see #previousDouble
1.442 + */
1.443 + public static final double nextDouble (double d) {
1.444 + return nextDouble(d,true);
1.445 + }
1.446 +
1.447 + /**
1.448 + * Finds the greatest double less than d.
1.449 + * If NaN, returns same value.
1.450 + * @see #nextDouble
1.451 + */
1.452 + public static final double previousDouble (double d) {
1.453 + return nextDouble(d,false);
1.454 + }
1.455 +
1.456 + /**
1.457 + * Overrides Cloneable
1.458 + */
1.459 + public Object clone()
1.460 + {
1.461 + ChoiceFormat other = (ChoiceFormat) super.clone();
1.462 + // for primitives or immutables, shallow clone is enough
1.463 + other.choiceLimits = (double[]) choiceLimits.clone();
1.464 + other.choiceFormats = (String[]) choiceFormats.clone();
1.465 + return other;
1.466 + }
1.467 +
1.468 + /**
1.469 + * Generates a hash code for the message format object.
1.470 + */
1.471 + public int hashCode() {
1.472 + int result = choiceLimits.length;
1.473 + if (choiceFormats.length > 0) {
1.474 + // enough for reasonable distribution
1.475 + result ^= choiceFormats[choiceFormats.length-1].hashCode();
1.476 + }
1.477 + return result;
1.478 + }
1.479 +
1.480 + /**
1.481 + * Equality comparision between two
1.482 + */
1.483 + public boolean equals(Object obj) {
1.484 + if (obj == null) return false;
1.485 + if (this == obj) // quick check
1.486 + return true;
1.487 + if (getClass() != obj.getClass())
1.488 + return false;
1.489 + ChoiceFormat other = (ChoiceFormat) obj;
1.490 + return (Arrays.equals(choiceLimits, other.choiceLimits)
1.491 + && Arrays.equals(choiceFormats, other.choiceFormats));
1.492 + }
1.493 +
1.494 + /**
1.495 + * After reading an object from the input stream, do a simple verification
1.496 + * to maintain class invariants.
1.497 + * @throws InvalidObjectException if the objects read from the stream is invalid.
1.498 + */
1.499 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1.500 + in.defaultReadObject();
1.501 + if (choiceLimits.length != choiceFormats.length) {
1.502 + throw new InvalidObjectException(
1.503 + "limits and format arrays of different length.");
1.504 + }
1.505 + }
1.506 +
1.507 + // ===============privates===========================
1.508 +
1.509 + /**
1.510 + * A list of lower bounds for the choices. The formatter will return
1.511 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
1.512 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
1.513 + * @serial
1.514 + */
1.515 + private double[] choiceLimits;
1.516 +
1.517 + /**
1.518 + * A list of choice strings. The formatter will return
1.519 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
1.520 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
1.521 + * @serial
1.522 + */
1.523 + private String[] choiceFormats;
1.524 +
1.525 + /*
1.526 + static final long SIGN = 0x8000000000000000L;
1.527 + static final long EXPONENT = 0x7FF0000000000000L;
1.528 + static final long SIGNIFICAND = 0x000FFFFFFFFFFFFFL;
1.529 +
1.530 + private static double nextDouble (double d, boolean positive) {
1.531 + if (Double.isNaN(d) || Double.isInfinite(d)) {
1.532 + return d;
1.533 + }
1.534 + long bits = Double.doubleToLongBits(d);
1.535 + long significand = bits & SIGNIFICAND;
1.536 + if (bits < 0) {
1.537 + significand |= (SIGN | EXPONENT);
1.538 + }
1.539 + long exponent = bits & EXPONENT;
1.540 + if (positive) {
1.541 + significand += 1;
1.542 + // FIXME fix overflow & underflow
1.543 + } else {
1.544 + significand -= 1;
1.545 + // FIXME fix overflow & underflow
1.546 + }
1.547 + bits = exponent | (significand & ~EXPONENT);
1.548 + return Double.longBitsToDouble(bits);
1.549 + }
1.550 + */
1.551 +
1.552 + static final long SIGN = 0x8000000000000000L;
1.553 + static final long EXPONENT = 0x7FF0000000000000L;
1.554 + static final long POSITIVEINFINITY = 0x7FF0000000000000L;
1.555 +
1.556 + /**
1.557 + * Finds the least double greater than d (if positive == true),
1.558 + * or the greatest double less than d (if positive == false).
1.559 + * If NaN, returns same value.
1.560 + *
1.561 + * Does not affect floating-point flags,
1.562 + * provided these member functions do not:
1.563 + * Double.longBitsToDouble(long)
1.564 + * Double.doubleToLongBits(double)
1.565 + * Double.isNaN(double)
1.566 + */
1.567 + public static double nextDouble (double d, boolean positive) {
1.568 +
1.569 + /* filter out NaN's */
1.570 + if (Double.isNaN(d)) {
1.571 + return d;
1.572 + }
1.573 +
1.574 + /* zero's are also a special case */
1.575 + if (d == 0.0) {
1.576 + double smallestPositiveDouble = Double.longBitsToDouble(1L);
1.577 + if (positive) {
1.578 + return smallestPositiveDouble;
1.579 + } else {
1.580 + return -smallestPositiveDouble;
1.581 + }
1.582 + }
1.583 +
1.584 + /* if entering here, d is a nonzero value */
1.585 +
1.586 + /* hold all bits in a long for later use */
1.587 + long bits = Double.doubleToLongBits(d);
1.588 +
1.589 + /* strip off the sign bit */
1.590 + long magnitude = bits & ~SIGN;
1.591 +
1.592 + /* if next double away from zero, increase magnitude */
1.593 + if ((bits > 0) == positive) {
1.594 + if (magnitude != POSITIVEINFINITY) {
1.595 + magnitude += 1;
1.596 + }
1.597 + }
1.598 + /* else decrease magnitude */
1.599 + else {
1.600 + magnitude -= 1;
1.601 + }
1.602 +
1.603 + /* restore sign bit and return */
1.604 + long signbit = bits & SIGN;
1.605 + return Double.longBitsToDouble (magnitude | signbit);
1.606 + }
1.607 +
1.608 + private static double[] doubleArraySize(double[] array) {
1.609 + int oldSize = array.length;
1.610 + double[] newArray = new double[oldSize * 2];
1.611 + System.arraycopy(array, 0, newArray, 0, oldSize);
1.612 + return newArray;
1.613 + }
1.614 +
1.615 + private String[] doubleArraySize(String[] array) {
1.616 + int oldSize = array.length;
1.617 + String[] newArray = new String[oldSize * 2];
1.618 + System.arraycopy(array, 0, newArray, 0, oldSize);
1.619 + return newArray;
1.620 + }
1.621 +
1.622 +}