/** * MathUtils.java 1.0 01/01/2001 * * (C) Benjamin Stark * (c) simone giannecchini */ package it.geosolutions.io.output; /**A class that contains several static utility methods. * * A class that contains several static methods for converting multiple bytes into * one float or integer. * * @author Benjamin Stark * @author Simone Giannecchini * @version 1.1 */ public final class MathUtils { //bitMask used to Mask data received static final int[] bitMask = { 0, 1, 3, 7, 15, 31, 63, 127, 255 }; /**Convert two bytes into a signed integer. * * Convert two bytes into a signed integer. * * @param a higher byte * @param b lower byte * * @return integer value */ public static int int2(final int a,final int b) { return (1 - ((a & 128) >> 6)) * ((((a & 255) & 127) << 8) | (b & 255)); } /**Convert three bytes into a signed integer. * * Convert three bytes into a signed integer. * * @param a higher byte * @param b middle part byte * @param c lower byte * * @return integer value */ public static int int3(final int a, final int b,final int c) { return (1 - ((a & 128) >> 6)) * ((((a & 255) & 127) << 16) | ((b & 255) << 8) | (c & 255)); } /**Convert four bytes into a signed integer. * * Convert four bytes into a signed integer. * * @param a highest byte * @param b higher middle byte * @param c lower middle byte * @param d lowest byte * * @return integer value */ public static int int4(final int a, final int b, final int c, final int d) { return (1 - ((a & 128) >> 6)) * ((((a & 255) & 127) << 24) | ((b & 255) << 16) | ((c & 255) << 8) | (d & 255)); } /**Convert two bytes into an unsigned integer. * * Convert two bytes into an unsigned integer. * * @param a higher byte * @param b lower byte * * @return integer value */ public static int uint2(final int a,final int b) { return ((a & 255) << 8) | (b & 255); } /**Convert three bytes into an unsigned integer. * * Convert three bytes into an unsigned integer. * * @param a higher byte * @param b middle byte * @param c lower byte * * @return integer value */ public static int uint3(final int a,final int b, final int c) { return ((a & 255) << 16) | ((b & 255) << 8) | (c & 255); } /**Convert four bytes into a float value. * * Convert four bytes into a float value. * * @param a highest byte * @param b higher byte * @param c lower byte * @param d lowest byte * * @return float value */ public static double IBM2FLoat(final int a,final int b,final int c,final int d) { boolean positive = true; int power = 0; int abspower = 0; int mant = 0; double value = 0.0; double exp = 0.0; positive = (a & 0x80) == 0; mant = MathUtils.uint3(b, c, d); power = (a & 0x7f) - 64; abspower = (power > 0) ? power : (-power); /* calc exp */ exp = 16.0; value = 1.0; while (abspower != 0) { if ((abspower & 1) != 0) { value *= exp; } exp = exp * exp; abspower >>= 1; } if (power < 0) { value = 1.0 / value; } value = (value * mant) / 16777216.0; if (!positive) { value = -value; } return value; } /**Converts a double to the standard IBM representation for a single precision real floating point number. * * Converts a float to the standard IBM representation for a single precision real floating point number. * This code is heavily based on code from gribw a c utility to encode * grib files (see <A HREF="http://www.cpc.ncep.noaa.gov/products/wesley/gribw.html"> * gribw(riter)</A> )}. * Many thanks to the author. */ public static byte[] Float2IBM(double fVal) { //ret value final byte[] ibm = new byte[4]; int sign = 0; int exp = 0; double mant = 0.0d; int imant = 0; //do we need to proceed if (fVal == 0.0) { return ibm; } //setting sign if (fVal < 0.0) { sign = 128; fVal = -fVal; } else { sign = 0; } mant = MathUtils.frexpMant(fVal); exp = MathUtils.frexpExp(fVal); if (mant >= 1.0) { mant = 0.5; exp++; } while ((exp & 3) != 0) { mant *= 0.5; exp++; } imant = (int) (Math.floor((mant * 256.0 * 256.0 * 256.0) + 0.5)); if (imant >= (256 * 256 * 256)) { imant = (int) (Math.floor((mant * 16.0 * 256.0 * 256.0) + 0.5)); exp -= 4; } exp = (exp / 4) + 64; if (exp < 0) { System.err.println("underflow in flt2ibm"); return null; } if (exp > 127) { System.err.println("overflow in flt2ibm"); //ibm[0] = (byte)(sign | 127); //ibm[1] = ibm[2] = ibm[3]=255; return null; } ibm[0] = (byte) (sign | exp); ibm[3] = (byte) (imant & 255); ibm[2] = (byte) ((imant >> 8) & 255); ibm[1] = (byte) ((imant >> 16) & 255); return ibm; } /**Convert an integer containing length bits into a vector of bytes. * * Convert an integer containing length bits into a vector of bytes. The most signifiant byte is returned * firs. The last byte contains the less signifiant part of the bitvector. * * @param bitVector int The bit vector to convert. * @param length int The number of bits in the vector. * * @return byte[] Byte vector. */ public static byte[] bitVector2ByteVector(final int bitVector,final int length) { if ((length <= 0) || (length > 32)) { return null; } //how many octets? final byte octetsNumber = (byte) Math.ceil(length / 8.0); //last octet bits number to read final byte lastOctetNumBits = (byte) (((length % 8) != 0) ? (length % 8) : 8); //return value final byte[] retVal = new byte[(byte) Math.ceil(length / 8.0)]; for (byte i = octetsNumber; i > 0; i--) { if (i == octetsNumber) { retVal[octetsNumber - i] = (byte) ((bitVector >> ((i - 1) * 8)) & MathUtils.bitMask[lastOctetNumBits]); } else { retVal[octetsNumber - i] = (byte) ((bitVector >> ((i - 1) * 8)) & MathUtils.bitMask[8]); } } //sign return retVal; } /**log2. * * log2. * * @param aFloat float */ static public double log2(final double val) { return (Math.log(val) / Math.log(2)); } /**exp2. * * exp2. * * @param val double */ static public double exp2(final double val) { return Math.exp(val * Math.log(2)); } /**signedInt2Bytes, converts a signed integer to a vector of bytes. * * signedInt2Bytes, converts a signed integer to a vector of bytes. */ static public byte[] signedInt2Bytes(int val, final int numBytes) { //sign boolean negative = false; if (val < 0) { negative = true; val = -val; } final byte[] retVal = new byte[numBytes]; switch (numBytes) { case 4: retVal[0] = ((byte) ((val >> 24) & 255)); retVal[1] = ((byte) ((val >> 16) & 255)); retVal[2] = ((byte) ((val >> 8) & 255)); retVal[3] = ((byte) ((val) & 255)); break; case 3: retVal[0] = ((byte) ((val >> 16) & 255)); retVal[1] = ((byte) ((val >> 8) & 255)); retVal[2] = ((byte) ((val) & 255)); break; case 2: retVal[0] = ((byte) ((val >> 8) & 255)); retVal[1] = ((byte) ((val) & 255)); break; case 1: retVal[0] = ((byte) ((val) & 255)); break; default: return null; } //SIGN retVal[0] |= (negative ? (1 << 7) : (0 << 7)); return retVal; } /**frexpMant, builds and gives the mantissa base 2 for the floating point representation of a real number. * * frexpMant, builds and gives the mantissa base 2 for the floating point representation of a real number. */ public static double frexpMant(final double val) { //getting ieee 754 representation int intBits = Float.floatToIntBits((float) val); //getting the mantissa out of it intBits &= ((int) Math.pow(2, 23) - 1); double mantissa = (intBits * Math.pow(2, -23)) + 1; //adding hidden bit //natissa should stay in between 1/2 and 1 mantissa /= 2; return mantissa; } /**frexpExp, builds and gives the exponent base 2 for the floating point representation of a real number. * * frexpExp, builds give the exponent base 2 for the floating point representation of a real number. */ public static byte frexpExp(final double val) { //getting ieee 754 representation int intBits = Float.floatToIntBits((float) val); //removing sign bit intBits >>>= 23; //shifting to get the sign intBits &= 0xff; //getting the sign intBits &= 255; //removing the bias intBits -= 127; //adding 1 because i have to take into account that ieee 754 single precision //deals with normalized mantissa using a hidden bit //terefore at the end the mantissa is 1.something //we need mantissa to be in between 1 and 1/2 return (byte) ++intBits; } }