/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2009, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package java.lang; import com.jopdesign.sys.Native; import com.jopdesign.sys.SoftFloat32; /** * @author ??? * */ public class VMFloat { public static String toString(float f) { return toString(Native.toInt(f)); } /** * A constant representing the same value as * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#POSITIVE_INFINITY">Float.POSITIVE_INFINITY</a> */ public static final int POSITIVE_INFINITY = 0x7f800000; /** * A constant holding the same value as * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#NEGATIVE_INFINITY">Float.NEGATIVE_INFINITY</a> */ public static final int NEGATIVE_INFINITY = 0xff800000; /** * A constant holding the same value as * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#NaN">Float.NaN</a> */ public static final int NaN = 0x7fc00000; /** A constant holding the value of 0.0d */ public static final int ZERO = 0x00000000; /** A constant holding the value of -0.0f */ public static final int NEGATIVE_ZERO = 0x80000000; /** A constant holding the value of 0.0d */ public static final int ONE = 0x3f800000; /** A constant holding the value of 2.0d */ public static final int TWO = 0x40000000; // base 10 exponents for 2 ^ -150 through 2 ^ 98, at intervals of 2 ^ 8 private static final byte[] pow2x = { -45, -42, -40, -37, -35, -33, -30, -28, -25, -23, -21, -18, -16, -13, -11, -9, -6, -4, -1, 1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, }; // base 2 mantissas for 10**-54 through 10**38, at intervals of 100 private static final int[] pow10m = { 0xc428d05b, 0x993fe2c7, 0xef73d257, 0xbb127c54, 0x92267121, 0xe45c10c4, 0xb267ed19, 0x8b61313c, 0xd9c7dced, 0xaa242499, 0x84ec3c98, 0xcfb11ead, 0xa2425ff7, 0xfd87b5f3, 0xc6120625, 0x9abe14cd, 0xf1c90081, 0xbce50865, 0x9392ee8f, 0xe69594bf, 0xb424dc35, 0x8cbccc09, 0xdbe6fecf, 0xabcc7712, 0x8637bd06, 0xd1b71759, 0xa3d70a3d, 0x80000000, 0xc8000000, 0x9c400000, 0xf4240000, 0xbebc2000, 0x9502f900, 0xe8d4a510, 0xb5e620f5, 0x8e1bc9bf, 0xde0b6b3a, 0xad78ebc6, 0x87867832, 0xd3c21bcf, 0xa56fa5ba, 0x813f3979, 0xc9f2c9cd, 0x9dc5ada8, 0xf684df57, 0xc097ce7c, 0x96769951, }; // base 2 exponents for 10**-54 through 10**38, at intervals of 100 private static final short[] pow10x = { -211, -204, -198, -191, -184, -178, -171, -164, -158, -151, -144, -138, -131, -125, -118, -111, -105, -98, -91, -85, -78, -71, -65, -58, -51, -45, -38, -31, -25, -18, -12, -5, 2, 8, 15, 22, 28, 35, 42, 48, 55, 62, 68, 75, 81, 88, 95, }; // base 10 mantissas for 2**-150 through 2**98, at intervals of 2**8 private static final int[] pow2m = { 0xb35dbf82, 0x2deaf18a, 0x758ca7c7, 0x1e17b843, 0x4d0985cb, 0xc5371912, 0x327cb273, 0x813f3979, 0x21165458, 0x54b40b20, 0xd8d726b7, 0x3782dacf, 0x8e1bc9bf, 0x246139cb, 0x5d21dba0, 0xee6b2800, 0x3d090000, 0x9c400000, 0x28000000, 0x66666666, 0x1a36e2eb, 0x431bde83, 0xabcc7712, 0x2bfaffc3, 0x709709a1, 0x1cd2b298, 0x49c97747, 0xbce50865, 0x305b6680, 0x7bcb43d7, 0x1fb0f6be, 0x51212ffc, }; /** @return true if d is negative */ static boolean unpackSign(int f) { return (f < 0); } private static int decToFloat(boolean negative, int base10x, int base10m) { if (base10m == 0) { return (negative ? NEGATIVE_ZERO : ZERO); } // maximize base10m to ensure consistency between toString and parseFloat while ((base10m > 0) && (base10m <= 0x19999999)) { // (Integer.MAX_VALUE / 5))) { base10m = (base10m << 3) + (base10m << 1); base10x--; } // base10x needs to be a multiple of 2, because the tables are // spaced at intervals of 100 (not 10). base10x += 54; boolean mod = ((base10x & 1) != 0); base10x >>= 1; if (base10x < 0) { // -54 return (negative ? NEGATIVE_ZERO : ZERO); } else if (base10x > 46) { // 38 return (negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY); } int base2x = pow10x[base10x]; long base2m = (base10m & 0xffffffffL) * (pow10m[base10x] & 0xffffffffL); if (mod) { if (base2m < 0) { base2m >>>= 1; base2x++; } base2m += base2m >>> 2; base2x += 3; } return SoftFloat32.pack(negative, base2x, base2m); } /** * Mimics * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#toString(float)">Float.toString(float)</a>. * <p> * <b>This implementation is known to be inaccurate, and * does not always return the same value as * <code>Float.toString</code>.</b> However the difference should be no * greater than 1 ulp. */ public static String toString(int f) { if (SoftFloat32.isNaN(f)) { return "NaN"; } boolean n = unpackSign(f); BoundedStringBuffer sb = new BoundedStringBuffer(15); if (n) { sb.append('-'); } if (SoftFloat32.isZero(f)) { sb.append("0.0"); return sb.toString(); } else if (SoftFloat32.isInfinite(f)) { sb.append("Infinity"); return sb.toString(); } // convert from base 2 to base 10 int base2x = SoftFloat32.unpackExponent(f); int base2m = SoftFloat32.unpackMantissa(f); int idx = base2x + 150; int dx = idx & 7; base2m <<= dx; idx >>= 3; int base10x = pow2x[idx]; while (base2m <= 0xccccccc) { base2m = (base2m << 3) + (base2m << 1); // base2m *= 10; base10x--; } long base10ml = base2m * (pow2m[idx] & 0xffffffffL); int base10m = (int) (base10ml >>> 32); if ((base10ml << 32) < 0) { base10m++; } // reduce the number of digits in m10 boolean roundedUp = false; while (true) { int r = base10m % 10; int mt = base10m / 10; int xt = base10x + 1; if (r != 0) { if ((r > 5) || ((r == 5) && (! roundedUp))) { roundedUp = true; mt++; } else { roundedUp = false; } int ft = decToFloat(n, xt, mt); if (ft != f) { if (roundedUp) { mt--; } else { mt++; } roundedUp ^= true; ft = decToFloat(n, xt, mt); if (ft != f) { break; } } } base10m = mt; base10x = xt; } // convert to string String s = Integer.toString(base10m); base10x += s.length() - 1; boolean scientific = ((base10x < -3) || (base10x >= 7)); int dp; // index of decimal point in final string if (scientific) { dp = 1; } else { dp = base10x + 1; if (dp < 1) { sb.append('0'); } } for (int i=0; i<dp; i++) { if (i < s.length()) { sb.append(s.charAt(i)); } else { sb.append('0'); } } sb.append('.'); if (dp >= s.length()) { sb.append('0'); } else { for (int i=dp; i<s.length(); i++) { if (i < 0) { sb.append('0'); } else { sb.append(s.charAt(i)); } } } if (scientific) { sb.append('E'); sb.append(Integer.toString(base10x)); } return sb.toString(); } public static String ftoa(int f,int frac_len) { int mantissa, int_part, frac_part; int exp2; String p=new String(); if (SoftFloat32.isZero(f)) { return "0.00"; } exp2 = ((f >>> 23) - 127); mantissa= (f & 0xFFFFFF) | 0x800000; frac_part = 0; int_part = 0; if (exp2 >= 31) { return "Too Large"; } else if (exp2 < -23) { return "Too Small"; } else if (exp2 >= 23) int_part = mantissa << (exp2 - 23); else if (exp2 >= 0) { int_part = mantissa >> (23 - exp2); frac_part = (mantissa << (exp2 + 1)) & 0xFFFFFF; } else /* if (exp2 < 0) */ frac_part = (mantissa & 0xFFFFFF) >> -(exp2 + 1); if (f < 0) p = "-"; if (int_part == 0) p = p+'0'; else { p=p+Integer.toString(int_part); } p = p+'.'; if (frac_part == 0) p = p+'0'; else { /* print BCD */ for (int m = 0; m < frac_len; m++) { /* frac_part *= 10; */ frac_part = (frac_part << 3) + (frac_part << 1); p = p+ (char)((frac_part >> 24) + 0x30); frac_part &= 0x00FFFFFF; } //ToDo: delete ending zeros } return p; } }