Java – How is a floating point number represented in Java

algorithmsfloating pointjava

Which algorithm does java uses to convert floating point number (Ex:0.15625) into binary(0.00101)?

Whether java uses normalized form or denormalized format?

If I type float ab=0.15625 in Java source file, which part of compiling and running the code will convert that floating point number into a format that could be stored in memory and used by the JVM?

Best Answer

The first thing to realize is that the binary representation of 0.15625 is not 0.00101. Yes, that is what you would write if you were writing out the number by hand. The actual representation of the number within the computer using IEE 754 for single precision 32 bit. This is specified as part of the Java Language Specification 4.2:

The floating-point types are float, whose values include the 32-bit IEEE 754 floating-point numbers, and double, whose values include the 64-bit IEEE 754 floating-point numbers.

The IEEE 754 binary representation of 0.15625 is: 0x3E200000 which can be broken down into:

  • a sign bit: 0 meaning it is positive.
  • the exponent for bits: 01111100 which is 124. This value is subtracted from 127 to get the actual exponent that will be used (-3)
  • the significand: .0100000 00000000 00000000. The . I put there is for reading so that it is bytes, not part of the value (the significant uses the lower 23 bits of the number... so the 24th bit I represent with a . so the alignment is easier to read) This value is added to 1 giving us the binary value of 1.010.... or in base 10, 1.25000...

Combining these all together, we get:

(-1)0 * 1.012 * 2-3 which comes out to be, when written, 0.00101. But remember, that we're really dealing with 0x3E200000.


Lets take a quick Java source file:

package com.michaelt.so.floating;

public class Demo {
    float foo = 0.15625f;
}

The byte code for this, when decompiled is:

// class version 50.0 (50)
// access flags 0x21
public class com/michaelt/so/floating/Demo {

  // compiled from: Demo.java

  // access flags 0x0
  F foo

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L1
    LINENUMBER 4 L1
    ALOAD 0
    LDC 0.15625
    PUTFIELD com/michaelt/so/floating/Demo.foo : F
    RETURN
   L2
    LOCALVARIABLE this Lcom/michaelt/so/floating/Demo; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1
}

Which really isn't too interesting. You can see the LDC 0.15625 in there which is a load constant opcode. It takes one argument from a constant pool and pushes it on the stack.

So, lets look at Demo.class with a hex dump viewer.

$ hexdump -C Demo.class 
00000000  ca fe ba be 00 00 00 32  00 15 0a 00 05 00 11 04  |.......2........|
00000010  3e 20 00 00 09 00 04 00  12 07 00 13 07 00 14 01  |> ..............|
00000020  00 03 66 6f 6f 01 00 01  46 01 00 06 3c 69 6e 69  |..foo...F...<ini|
00000030  74 3e 01 00 03 28 29 56  01 00 04 43 6f 64 65 01  |t>...()V...Code.|
00000040  00 0f 4c 69 6e 65 4e 75  6d 62 65 72 54 61 62 6c  |..LineNumberTabl|
00000050  65 01 00 12 4c 6f 63 61  6c 56 61 72 69 61 62 6c  |e...LocalVariabl|
00000060  65 54 61 62 6c 65 01 00  04 74 68 69 73 01 00 1f  |eTable...this...|
00000070  4c 63 6f 6d 2f 6d 69 63  68 61 65 6c 74 2f 73 6f  |Lcom/michaelt/so|
00000080  2f 66 6c 6f 61 74 69 6e  67 2f 44 65 6d 6f 3b 01  |/floating/Demo;.|
00000090  00 0a 53 6f 75 72 63 65  46 69 6c 65 01 00 09 44  |..SourceFile...D|
000000a0  65 6d 6f 2e 6a 61 76 61  0c 00 08 00 09 0c 00 06  |emo.java........|
000000b0  00 07 01 00 1d 63 6f 6d  2f 6d 69 63 68 61 65 6c  |.....com/michael|
000000c0  74 2f 73 6f 2f 66 6c 6f  61 74 69 6e 67 2f 44 65  |t/so/floating/De|
000000d0  6d 6f 01 00 10 6a 61 76  61 2f 6c 61 6e 67 2f 4f  |mo...java/lang/O|
000000e0  62 6a 65 63 74 00 21 00  04 00 05 00 00 00 01 00  |bject.!.........|
000000f0  00 00 06 00 07 00 00 00  01 00 01 00 08 00 09 00  |................|
00000100  01 00 0a 00 00 00 39 00  02 00 01 00 00 00 0b 2a  |......9........*|
00000110  b7 00 01 2a 12 02 b5 00  03 b1 00 00 00 02 00 0b  |...*............|
00000120  00 00 00 0a 00 02 00 00  00 03 00 04 00 04 00 0c  |................|
00000130  00 00 00 0c 00 01 00 00  00 0b 00 0d 00 0e 00 00  |................|
00000140  00 01 00 0f 00 00 00 02  00 10                    |..........|
0000014a

Look, right there at the start of the second line...

00000010  3e 20 00 00

There's the number.


Someone is going to ask 'but why is the number way up there? There's not even a 12 near it (the hex value for LDC).' And they are right to ask this. Remember that the LDC tool a value from the constant pool. The byte code that I had earlier was converted back into something a person could read.

The structure of a class file can be found in the Java Virtual Machine Specification section 4.1:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

We've got the magic number at the top (ca fe ba be), and the minor version (00 00), and major version (00 32 = 5010) and then the constant pool count (00 15) which then has the constant pool itself.

The constant pool is specified in section 4.4 which has the format:

cp_info {
    u1 tag;
    u1 info[];
}

The tag value of 04 says that 'what is next is a float`. You can see it at the end of the preceding line.

00000000  ca fe ba be 00 00 00 32  00 15 0a 00 05 00 11 04  |.......2........|
00000010  3e 20 00 00 09 00 04 00  12 07 00 13 07 00 14 01  |> ..............|

The other stuff that is around the number is information about locations for methods (it still has a default constructor), the name of the field, the name of the class, etc... there are a bunch of constants in there.

The key thing there though, you can see the floating point number stored in the class file as an IEEE 754 value that indicates this is something that the compiler does.