Muhammad Adeel
Muhammad Adeel

Reputation: 2884

How to read binary 32-bit fixed-point number in Java

I need to read Adobe's signed 32-bit fixed-point number, with 8 bits for the integer part followed by 24 bits for the fractional part. This is a "path point", as defined in Adobe Photoshop File Formats Specification.

This is how I'd do it in Ruby, but I need to do it in Java.

  read(1).unpack('c*')[0].to_f +
    (read(3).unpack('B*')[0].to_i(2).to_f / (2 ** 24)).to_f

Upvotes: 0

Views: 607

Answers (2)

AJMansfield
AJMansfield

Reputation: 4175

Based on some discussion in the comments of David Wallace's answer, there is a significantly faster way to compute the correct double.

Probably the very fastest way to convert it is like this:

double intFixedPoint24ToDouble(int bits){
    return ((double) bits) / 1<<24;
}

The reason that this is faster is because of the way double-precision floating point arithmatic works. In this case, the above sequence can be converted to some extremely simple additions and bit shifting. When this gets run, the actual steps it takes look like this:

  1. Convert an int (bits) to a double (done on FPU, usually). This is quite fast.
  2. Subtract 0x00180000 from the upper 32 bits of that result. This is extremely fast.

A very similar optimization can be applied whenever you multiply or divide any floating point number by any compile-time constant integer that is a power of two.

This compiler optimization does not apply if you are instead dividing by a double, or if you divide by a non-compile-time-constant expression (any expression involving anything other than final compile-time-constant variables, literal numbers, or operators). In that case, it must be performed as a double-precision floating-point division, which is probably the slowest single operation, except for block transfers and advanced mathematical functions.

However, as you can see, 1<<24 is a compile-time constant power of two, and so the optimization does apply in this case.

Upvotes: 2

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79877

Read your bytes into an int (which is always 32 bits in Java), then use this. You need double, not float, because single precision floating point won't necessarily be long enough to hold your 32 bit fixed point number.

double toFixedPoint(int bytes){
    return bytes / Math.pow(2, 24);
}

If speed is a concern, then work out Math.pow(2,24) outside of this method and store it.

Upvotes: 0

Related Questions