blob: 13ec12f48b6c7cbd253b5d6f52e25d8a108ee124 [file] [log] [blame]
package co.nstant.in.cbor.encoder;
import java.io.OutputStream;
import co.nstant.in.cbor.CborEncoder;
import co.nstant.in.cbor.CborException;
import co.nstant.in.cbor.model.HalfPrecisionFloat;
public class HalfPrecisionFloatEncoder extends AbstractEncoder<HalfPrecisionFloat> {
public HalfPrecisionFloatEncoder(CborEncoder encoder, OutputStream outputStream) {
super(encoder, outputStream);
}
@Override
public void encode(HalfPrecisionFloat dataItem) throws CborException {
write((7 << 5) | 25);
int bits = fromFloat(dataItem.getValue());
write((bits >> 8) & 0xFF);
write((bits >> 0) & 0xFF);
}
/**
* @see <a href="http://stackoverflow.com/a/6162687">Stack Overflow</a>
*/
// returns all higher 16 bits as 0 for all results
public static int fromFloat(float fval) {
int fbits = Float.floatToIntBits(fval);
int sign = fbits >>> 16 & 0x8000; // sign only
int val = 0x1000 + fbits & 0x7fffffff; // rounded value
if (val >= 0x47800000) // might be or become NaN/Inf
{ // avoid Inf due to rounding
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) // round depending on cut off
>>> 126 - val); // div by 2^(1-(exp-127+15)) and >> 13 | exp=0
}
}