/************************************************************************** * Copyright (c) 2005 by Chris Gray, /k/ Embedded Java Solutions. * * All rights reserved. * **************************************************************************/ package java.lang; /** * A helper class for java.lang.Math; only visible within java.lang. * This version contains all-java implementations of the various algorithms; * see under the math/java source tree for a version using native code. */ class MathHelper { /** ** Convert a float when we already know that ** it is finite, positive, non-Nan, and between 0.001 and 10000000. **<p>As with so many things, the problem is knowing when to stop. ** We want to print just enough digits so that when the result is ** converted back to an ideal (infinite precision) real number, the ** closest number to that real number that can be represented as a ** float is the number we started with. Our approach is to calculate ** delta = the difference between the float we are printing and the ** adjacent floats, and to stop when we are within delta of our target. */ static String toString_internal(float absvalue) { float delta = (absvalue - Float.intBitsToFloat(Float.floatToIntBits(absvalue) - 1)); float residue = absvalue - (int)absvalue; StringBuffer buffer = new StringBuffer(32); buffer.append((int)absvalue); buffer.append('.'); double pow10 = 10.0; int nextdigit = (int)(residue * pow10); buffer.append(Character.forDigit(nextdigit, 10)); residue -= nextdigit / pow10; while (residue > delta) { pow10 *= 10.0; nextdigit = (int)(residue * pow10); if (nextdigit < 9 && ((nextdigit+1) / pow10) - residue < delta) { ++nextdigit; } buffer.append(Character.forDigit(nextdigit, 10)); residue -= nextdigit / pow10; } return buffer.toString(); } /** ** Convert a double when we already know that ** it is finite, positive, non-Nan, and between 0.001 and 10000000. **<p>As with so many things, the problem is knowing when to stop. ** We want to print just enough digits so that when the result is ** converted back to an ideal (infinite precision) real number, the ** closest number to that real number that can be represented as a ** double is the number we started with. Our approach is to calculate ** delta = the difference between the double we are printing and an ** adjacent double, and to stop when we are within delta of our target. */ static String toString_internal(double absvalue) { double delta = (absvalue - Double.longBitsToDouble(Double.doubleToLongBits(absvalue) ^ 1)); if (delta < 0) { delta = -delta; } double residue = absvalue - (int)absvalue; StringBuffer buffer = new StringBuffer(32); buffer.append((int)absvalue); buffer.append('.'); double pow10 = 10.0; int nextdigit = (int)(residue * pow10); buffer.append((char)('0'+nextdigit)); /* WAS : residue -= nextdigit / pow10; while (residue > delta) { pow10 *= 10.0; nextdigit = (int)(residue * pow10); buffer.append((char)('0'+nextdigit)); residue -= nextdigit / pow10; } */ /* THEN WE TRIED: double powmin10 = 0.1; double sofar = (int)absvalue + nextdigit * powmin10; residue = absvalue - sofar; while (residue > delta) { pow10 *= 10.0; powmin10 /= 10.0; nextdigit = (int)(residue * pow10); buffer.append((char)('0'+nextdigit)); sofar += nextdigit * powmin10; residue = absvalue - sofar; } */ residue *= 10.0; delta *= 10.0; residue -= nextdigit; while (residue > delta) { nextdigit = (int)(residue * pow10); buffer.append((char)('0'+nextdigit)); residue *= 10.0; delta *= 10.0; residue -= nextdigit; } boolean carry; int l = buffer.length(); if(l >= 18 ) { int k = -1; int d17 = Character.forDigit(buffer.charAt(17), 10); // int d18 = l > 18 ? Character.forDigit(buffer.charAt(18), 10) : 5; // carry = residue > delta * 0.5 || d18 > 5 || d17 == 9 || (d18 == 5 /* && (d17 % 2) == 1 */ ); if (l > 18 && d17 > 5) { // HACK HACK HACK buffer.setCharAt(17, '9'); d17 = 9; } carry = residue > delta * 0.5 || d17 == 9 || l > 18; l = 18; if (carry) { while (l > 0 && carry) { char ch = buffer.charAt(l - 1); switch (ch) { case '.': k = l; --l; break; case '9': buffer.setCharAt(--l, '0'); break; default: buffer.setCharAt(l - 1, (char)(ch + 1)); carry = false; } } if (carry) { buffer.insert(0, '1'); ++k; ++l; } if (k > l) { l = k + 1; } } else { while (buffer.charAt(l - 1) == '0') { --l; } if (buffer.charAt(l - 1) == '.') { ++l; } } buffer.setLength(l); } // BEGIN UGLY HACK /* if (l > 16 && buffer.substring(l - 9, l - 1).equals("99999999")) { // System.out.println("HACK HACK HACK : WAS " + buffer.toString()); l -= 9; int k = 0; carry = true; while (l > 0 && carry) { char ch = buffer.charAt(l - 1); switch (ch) { case '.': k = l; --l; break; case '9': buffer.setCharAt(--l, '0'); break; default: buffer.setCharAt(l - 1, (char)(ch + 1)); carry = false; } } if (carry) { buffer.insert(0, '1'); ++k; ++l; } buffer.setLength(k > l ? k + 1 : l); // System.out.println("HACK HACK HACK : NOW " + buffer.toString()); } else if (l > 17 && buffer.substring(l - 9, l - 1).equals("00000000")) { // System.out.println("HACK HACK HACK : WAS " + buffer.toString()); l -= 9; while (buffer.charAt(l - 1) == '0') { --l; } if (buffer.charAt(l - 1) == '.') { ++l; } buffer.setLength(l); // System.out.println("HACK HACK HACK : NOW " + buffer.toString()); } */ // END UGLY HACK //System.out.println("translated '"+Long.toHexString(Double.doubleToLongBits(absvalue))+"' to '"+buffer+"'"); return buffer.toString(); } }