![JAR search and dependency download from the Maven repository](/logo.png)
com.ning.billing.meter.timeline.samples.HalfFloat Maven / Gradle / Ivy
/*
* Copyright 2010-2012 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.ning.billing.meter.timeline.samples;
public class HalfFloat {
private final short halfFloat;
public HalfFloat(final float input) {
halfFloat = (short)fromFloat(input);
}
public float getFloat() {
return toFloat((int)halfFloat);
}
// These two static methods were pinched from http://stackoverflow.com/questions/6162651/half-precision-floating-point-in-java/6162687#6162687
// The last comments on that page is the author saying "I hereby commit these to the public domain"
// Ignores the higher 16 bits
public static float toFloat(final int hbits) {
int mant = hbits & 0x03ff; // 10 bits mantissa
int exp = hbits & 0x7c00; // 5 bits exponent
if (exp == 0x7c00) { // NaN/Inf
exp = 0x3fc00; // -> NaN/Inf
}
else if (exp != 0) { // normalized value
exp += 0x1c000; // exp - 15 + 127
if(mant == 0 && exp > 0x1c400) { // smooth transition
return Float.intBitsToFloat((hbits & 0x8000) << 16 | exp << 13 | 0x3ff);
}
}
else if (mant != 0) { // && exp==0 -> subnormal
exp = 0x1c400; // make it normal
do {
mant <<= 1; // mantissa * 2
exp -= 0x400; // decrease exp by 1
} while ((mant & 0x400) == 0); // while not normal
mant &= 0x3ff; // discard subnormal bit
} // else +/-0 -> +/-0
return Float.intBitsToFloat( // combine all parts
(hbits & 0x8000) << 16 // sign << (31 - 15)
| (exp | mant) << 13); // value << (23 - 10)
}
// returns all higher 16 bits as 0 for all results
public static int fromFloat(final float fval) {
final int fbits = Float.floatToIntBits(fval);
final int sign = fbits >>> 16 & 0x8000; // sign only
int val = (fbits & 0x7fffffff) + 0x1000; // rounded value
if (val >= 0x47800000) { // might be or become NaN/Inf
if ((fbits & 0x7fffffff) >= 0x47800000) { // is or must become NaN/Inf
if (val < 0x7f800000) { // was value but too large
return sign | 0x7c00; // make it +/-Inf
}
return sign | 0x7c00 | // remains +/-Inf or NaN
(fbits & 0x007fffff) >>> 13; // keep NaN (and Inf) bits
}
return sign | 0x7bff; // unrounded not quite Inf
}
if(val >= 0x38800000) // remains normalized value
return sign | val - 0x38000000 >>> 13; // exp - 127 + 15
if(val < 0x33000000) // too small for subnormal
return sign; // becomes +/-0
val = (fbits & 0x7fffffff) >>> 23; // tmp exp for subnormal calc
return sign | ((fbits & 0x7fffff | 0x800000) // add subnormal bit
+ (0x800000 >>> val - 102) >>> 126 - val); // round depending on cut off; div by 2^(1-(exp-127+15)) and >> 13 | exp=0
}
private static String describe(final int halfFloat) {
final int sign = (halfFloat >> 15) & 1;
final int exponent = (halfFloat >> 10) & 0x1f;
final double fraction = (double)(0x400 + (halfFloat & 0x3ff)) / (1.0 * 0x400);
final double product = fraction * Math.pow(2.0, exponent - 15) * (sign == 0 ? 1.0 : -1.0);
return String.format("HalfFloat %f, representation %x, sign %d, exponent 0x%x == 2**%d, fraction %f, product %f",
toFloat(halfFloat),
halfFloat,
sign,
exponent,
exponent - 15,
fraction,
product);
}
public static void main(String[] args) {
System.out.printf("%f double-converted = %f\n", 200.0, toFloat(fromFloat((float)200.0)));
System.out.printf("%s\n", describe(fromFloat(200.0f)));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy