Example #1
0
 /**
  * Converts a string representation of a real number into a DoubleDouble value. The format
  * accepted is similar to the standard Java real number syntax. It is defined by the following
  * regular expression:
  *
  * <pre>
  * [<tt>+</tt>|<tt>-</tt>] {<i>digit</i>} [ <tt>.</tt> {<i>digit</i>} ] [ ( <tt>e</tt> | <tt>E</tt> ) [<tt>+</tt>|<tt>-</tt>
  * ] {<i>digit</i>}+
  *
  * </pre>
  *
  * @param str the string to parse
  * @return the value of the parsed number
  * @throws NumberFormatException if <tt>str</tt> is not a valid representation of a number
  */
 public static WB_DoubleDouble parse(final String str) throws NumberFormatException {
   int i = 0;
   final int strlen = str.length();
   // skip leading whitespace
   while (Character.isWhitespace(str.charAt(i))) {
     i++;
   }
   // check for sign
   boolean isNegative = false;
   if (i < strlen) {
     final char signCh = str.charAt(i);
     if ((signCh == '-') || (signCh == '+')) {
       i++;
       if (signCh == '-') {
         isNegative = true;
       }
     }
   }
   // scan all digits and accumulate into an integral value
   // Keep track of the location of the decimal point (if any) to allow
   // scaling later
   final WB_DoubleDouble val = new WB_DoubleDouble();
   int numDigits = 0;
   int numBeforeDec = 0;
   int exp = 0;
   while (true) {
     if (i >= strlen) {
       break;
     }
     final char ch = str.charAt(i);
     i++;
     if (Character.isDigit(ch)) {
       final double d = ch - '0';
       val.selfMultiply(TEN);
       // MD: need to optimize this
       val.selfAdd(d);
       numDigits++;
       continue;
     }
     if (ch == '.') {
       numBeforeDec = numDigits;
       continue;
     }
     if ((ch == 'e') || (ch == 'E')) {
       final String expStr = str.substring(i);
       // this should catch any format problems with the exponent
       try {
         exp = Integer.parseInt(expStr);
       } catch (final NumberFormatException ex) {
         throw new NumberFormatException("Invalid exponent " + expStr + " in string " + str);
       }
       break;
     }
     throw new NumberFormatException(
         "Unexpected character '" + ch + "' at position " + i + " in string " + str);
   }
   WB_DoubleDouble val2 = val;
   // scale the number correctly
   final int numDecPlaces = numDigits - numBeforeDec - exp;
   if (numDecPlaces == 0) {
     val2 = val;
   } else if (numDecPlaces > 0) {
     final WB_DoubleDouble scale = TEN.pow(numDecPlaces);
     val2 = val.divide(scale);
   } else if (numDecPlaces < 0) {
     final WB_DoubleDouble scale = TEN.pow(-numDecPlaces);
     val2 = val.multiply(scale);
   }
   // apply leading sign, if any
   if (isNegative) {
     return val2.negate();
   }
   return val2;
 }
Example #2
0
 /**
  * Extracts the significant digits in the decimal representation of the argument. A decimal point
  * may be optionally inserted in the string of digits (as long as its position lies within the
  * extracted digits - if not, the caller must prepend or append the appropriate zeroes and decimal
  * point).
  *
  * @param insertDecimalPoint the insert decimal point
  * @param magnitude the magnitude
  * @return the string containing the significant digits and possibly a decimal point
  */
 private String extractSignificantDigits(final boolean insertDecimalPoint, final int[] magnitude) {
   WB_DoubleDouble y = this.abs();
   // compute *correct* magnitude of y
   int mag = magnitude(y.hi);
   final WB_DoubleDouble scale = TEN.pow(mag);
   y = y.divide(scale);
   // fix magnitude if off by one
   if (y.gt(TEN)) {
     y = y.divide(TEN);
     mag += 1;
   } else if (y.lt(ONE)) {
     y = y.multiply(TEN);
     mag -= 1;
   }
   final int decimalPointPos = mag + 1;
   final StringBuffer buf = new StringBuffer();
   final int numDigits = MAX_PRINT_DIGITS - 1;
   for (int i = 0; i <= numDigits; i++) {
     if (insertDecimalPoint && (i == decimalPointPos)) {
       buf.append('.');
     }
     final int digit = (int) y.hi;
     // System.out.println("printDump: [" + i + "] digit: " + digit +
     // "  y: " + y.dump() + "  buf: " + buf);
     /** This should never happen, due to heuristic checks on remainder below */
     if ((digit < 0) || (digit > 9)) {
       // System.out.println("digit > 10 : " + digit);
       // throw new
       // IllegalStateException("Internal errror: found digit = " +
       // digit);
     }
     /**
      * If a negative remainder is encountered, simply terminate the extraction. This is robust,
      * but maybe slightly inaccurate. My current hypothesis is that negative remainders only occur
      * for very small lo components, so the inaccuracy is tolerable
      */
     if (digit < 0) {
       break;
       // throw new
       // IllegalStateException("Internal errror: found digit = " +
       // digit);
     }
     boolean rebiasBy10 = false;
     char digitChar = 0;
     if (digit > 9) {
       // set flag to re-bias after next 10-shift
       rebiasBy10 = true;
       // output digit will end up being '9'
       digitChar = '9';
     } else {
       digitChar = (char) ('0' + digit);
     }
     buf.append(digitChar);
     y = (y.subtract(WB_DoubleDouble.valueOf(digit)).multiply(TEN));
     if (rebiasBy10) {
       y.selfAdd(TEN);
     }
     boolean continueExtractingDigits = true;
     /**
      * Heuristic check: if the remaining portion of y is non-positive, assume that output is
      * complete
      */
     // if (y.hi <= 0.0)
     // if (y.hi < 0.0)
     // continueExtractingDigits = false;
     /**
      * Check if remaining digits will be 0, and if so don't output them. Do this by comparing the
      * magnitude of the remainder with the expected precision.
      */
     final int remMag = magnitude(y.hi);
     if ((remMag < 0) && (Math.abs(remMag) >= (numDigits - i))) {
       continueExtractingDigits = false;
     }
     if (!continueExtractingDigits) {
       break;
     }
   }
   magnitude[0] = mag;
   return buf.toString();
 }