// The "Minifloat" class. public class Minifloat { private char bits [] = new char [8]; private int getSign () { return (int) bits [0] - '0'; } private int getExponent () { // Find the absolute value of the exponent int exp = 0; for (int i = 1 ; i < 4 ; i++) exp = exp * 2 + (bits [i] - '0'); // Find its value in excess 3 exp = exp - 3; return exp; } // Returns 0 .. 15, corresponding to the mantissa's bit pattern private int getMantissa () { // Find the absolute value of the mantissa int man = 0; for (int i = 4 ; i < 8 ; i++) man = man * 2 + (bits [i] - '0'); return man; } private char bitsAsChar; public double getValue () { double mantissa = 1 /* hidden bit! */ + getMantissa () / 16.0; double result = 0.0; //System.out.println ("Mantissa: " + mantissa); int exp = getExponent (); if (exp == -3) // i.e., if the exponent is 000 binary { // Mantissa (without hidden bit) is considered the // "denormalized" magnitude of the number shifted // left 3 - 1 == 2 places (i.e., multiplied by 2^(1 - 3)) result = (mantissa - 1) / 4; // Note that 0.0 and -0.0 are special cases of // denormalized numbers } else if (exp < 0) { result = mantissa; for (int i = exp ; i < 0 ; i++) result = result / 2; } else if (exp == 4) { // Exponent is all 1s, either infinity or Not a Number (NaN) if (mantissa == 1.0) result = Float.POSITIVE_INFINITY; else result = Float.NaN; } else // if ((exp > 0) && (exp < 4)) { result = mantissa; for (int i = 0 ; i < exp ; i++) result = result * 2; } if (getSign () == 1) result = -result; return result; } public String getBitString () { String s = ""; for (int i = 0 ; i < bits.length ; i++) s = s + bits [i]; return s; } public static Minifloat bitsToMinifloat (char newBits []) { Minifloat result = new Minifloat (); for (int i = 0 ; i < Math.max (newBits.length, result.bits.length) ; i++) result.bits [i] = newBits [i]; return result; } public void setValue (double newValue) { // We may not need much of this, but... char rawBits [] = new char [64]; for (int i = 0 ; i < rawBits.length ; i++) rawBits [i] = '0'; String s = Long.toBinaryString (Double.doubleToLongBits (newValue)); while (s.length () < 64) s = '0' + s; s.getChars (0, s.length (), rawBits, 0); // s now looks like a bit string version of newValue // Next, take care of the sign bit... bits [0] = rawBits [0]; // And remove it from further consideration if (bits [0] == '1') newValue = -newValue; //System.out.println (newValue); if (newValue > 0.0 && newValue < 1.0 / 64.0) // +underflow (i.e. < epsilon)? { //System.out.println ("Got here. newValue is " + newValue); for (int i = 1 ; i < bits.length ; i++) // yes, then make +/-0.0 bits [i] = '0'; //System.out.println ("underflow"); } else if (newValue < 0.25) // must be normalized? { // yes // Zero the exponent... for (int i = 1 ; i <= 3 ; i++) bits [i] = '0'; // Set the mantissa (bit-shifted left twice)... double denom = 8.0; for (int i = 4 ; i <= 7 ; i++) { if (newValue >= 1.0 / denom) { bits [i] = '1'; newValue = newValue - 1.0 / denom; } else bits [i] = '0'; denom *= 2; } //System.out.println ("normalized"); } else if (newValue > 15.5) // +overflow? { for (int i = 1 ; i <= 7 ; i++) // yes, then make +/- infinity bits [i] = '1'; // Note: Only the exponent bits have to // be '1' to signify infinity, but // by making all bits '1' I get round // the need for making a second loop // to fill bits 4..7 with '0'. //System.out.println ("overflow"); } else { // Copy the exponent bits [1] = rawBits [1]; bits [2] = rawBits [10]; bits [3] = rawBits [11]; //System.out.println (bits [1] + "" + bits [2] + "" + bits [3]); // Copy the mantissa for (int i = 4 ; i <= 7 ; i++) bits [i] = rawBits [i + 8]; } } public Minifloat (double initialValue) { setValue (initialValue); } public Minifloat () { for (int i = 0 ; i < bits.length ; i++) bits [i] = '0'; } public String toString () { return "" + getValue (); } // Note: newExp should be in the range -3 .. 4 private void setExponent (int newExp) { newExp = newExp + 3; // Force into excess-3 for (int i = 3 ; i > 0 ; i--) { bits [i] = (char) (newExp % 2 + '0'); newExp /= 2; } } // Note: bitStr should be in the range "000" .. "111" private void setExponent (String bitStr) { for (int i = 1 ; i < 4 ; i++) bits [i] = bitStr.charAt (i - 1); } // Note: newMant should be in the range 0 .. 15 private void setMantissa (int newMant) { for (int i = 7 ; i > 3 ; i--) { bits [i] = (char) (newMant % 2 + '0'); newMant /= 2; } } //Note: bitStr should be in the range "0000" .. "1111" private void setMantissa (String bitStr) { for (int i = 4 ; i < 8 ; i++) bits [i] = bitStr.charAt (i - 4); } private void makeNaN () { bits [0] = '0'; setExponent ("111"); setMantissa ("1000"); // Java style } private void makeInfinity (int sign) { if (sign == 0) bits [0] = '0'; else bits [0] = '1'; setExponent ("111"); setMantissa ("0000"); } public void add (Minifloat other) { int thisMant = getMantissa (); int thisExp = getExponent (); int otherMant = other.getMantissa (); int otherExp = other.getExponent (); if (thisExp != -3) thisMant += 16; else { thisMant /= 4; thisExp = 0; } if (otherExp != -3) otherMant += 16; else { otherMant /= 4; otherExp = 0; } while (thisExp > otherExp) { otherExp = otherExp + 1; otherMant = otherMant / 2; } while (thisExp < otherExp) { thisExp = thisExp + 1; thisMant = thisMant / 2; } // if exponents were not equal before, they are now int thisSignMult = bits [0] == '0' ? 1 : -1; int otherSignMult = other.bits [0] == '0' ? 1 : -1; int sumMants = thisSignMult * thisMant + otherSignMult * otherMant; // Set sign bit if (sumMants < 0) { bits [0] = '1'; sumMants = -sumMants; } else bits [0] = '0'; if (sumMants >= 32) { thisExp += 1; sumMants /= 2; } if (thisExp >= 4) // Check for overflow makeInfinity (bits [0] - '0'); else if (sumMants == 0) { // Sum is 0.0 or -0.0 setExponent (-3); // 0 in excess-3 setMantissa (0); } else // All okay { //System.out.println (thisExp); setExponent (thisExp); // Hide hidden bit again setMantissa (sumMants - 16); } } } // Minifloat class