tonihele
tonihele

Reputation: 49

Reading 10-bit fixed-point float

I have a binary file that contains 10-bit fixed point values that I need to convert to Java float. I'm almost certain that the "format" is x.xxxxxxxxx, where x is a bit. And I do think I understand the basics of doing this by hand.

I would have to do to the bits: x + 0.5*x + 0,25*x... etc. For example

1010110010 = 1×1 + 0×½ + 1×¼ + 0×⅛ + 1×¹⁄₁₆ + 1×¹⁄₃₂...

But I have no idea how to do this in Java. I can read the file only one BYTE at a time, one value would be reading 2 bytes = 16 bits.

The file is in LITTLE ENDIAN.

Upvotes: 1

Views: 1020

Answers (5)

phuclv
phuclv

Reputation: 41942

Alternatively just construct the float directly from the raw bits

Assuming the binary value is read into the low 10 bits of v

if (v == 0)
   return 0.0f;

// shift the mantissa to the correct position and drop the implicit 1 bit
int mantissa = (v << (23 - Integer.highestOneBit(v))) & 0x7ffff;
int exponent = (-9 + 127) << 23;

return Float.intBitsToFloat(mantissa | exponent);

Upvotes: 0

Joop Eggen
Joop Eggen

Reputation: 109593

The conversion from bytes to 10-bit raw ints could be like this:

Path file = Paths.get("....");
byte[] data = Files.readAllBytes(file);

// data is a sequence of 10 bit fixed-point floats
if (data.length % 5 != 0) {
    throw new IllegalArgumentException(
        "File length is not a multiple of 10 bits: " + file);
}
int bitCount = data.length * 8;
bitCount = bitCount - (bitCount % 10); // When without check.
int[] rawInts = new int[bitCount / 10];
for (int bitIx = 0; bitIx < bitCount; bitIx += 10) {
    int byteIx0 = bitIx / 8;
    int byte0 = data[byteIx0) & 0xFF;
    int byteIx1 = byteIx0 + 1;
    int byte1 = data[byteIx1) & 0xFF;
    int off = bitIx % 8;

    int rawInt = ((byte0 << off + 2) & 0x3FF)
        | (byte1 >> (8 - (2 + off));
    rawInts[bitIx / 10] = rawInt;
}

Now to the fixed point format: with 10 bits one has 210 numbers, hence 0 .. 1023. This suggests that the fixed point is based around 1000, maybe 9.99

int integralPart = rawInt / 100;
int decimals = rawInt % 100;

P.S. not tested the bit shifting, which by the way could also be little endian.

Upvotes: 0

Hot Licks
Hot Licks

Reputation: 47739

If you have 10 bits, and the "binary point" is between the first and second bits, that just means the number is divided by 2 to the 9th, or 512. So put the value in the low end of an int, cast to float, divide by 512, and you have your number.

float finalAnswer = bitsInLowOrderEndOfInt / 512.0;

Upvotes: 2

Peter Lawrey
Peter Lawrey

Reputation: 533710

Instead of computing each bit, it is more efficient to calculate the exponent.

public double parse (InputStream is) {
    long value = 0, factor = 0;
    for(;;) {
        int ch = is.read();
        if (ch == '.') {
            factor = 1;
        } else if(ch == '0' || ch = '1') {
            factor *= 2;
            value = value * 2 + ch - '0';
        } else {
            break;
        }
    }
    return factor == 0 ? value : (double) value / factor;
}

Upvotes: 1

msrd0
msrd0

Reputation: 8390

I would have to do to the bits: x,0.5*x+0.25*x.... etc.

That's actually not difficult in Java. Assuming you converted the bits into booleans, your code can look like this:

public double parse (boolean ... bits)
{
    double val = (bits[0] ? 1 : 0); // note to check that bits[0] exists
    for (int i = 1; i < bits.length; i++)
        val += (1.0 / 2*i) * (bits[i] ? 1 : 0) * Math.pow(2, -1*i);
    return val;
}

Upvotes: 0

Related Questions