Come è rappresentato un numero in virgola mobile in Java?

2

Quale algoritmo utilizza java per convertire il numero in virgola mobile (Es: 0,15625) in binario (0,00101)?

Se java utilizza la forma normalizzata o il formato denormalizzato?

Se scrivo float ab=0.15625 nel file sorgente Java, quale parte della compilazione ed esecuzione del codice convertirà quel numero in virgola mobile in un formato che potrebbe essere memorizzato e utilizzato dalla JVM?

    
posta Harish_N 13.09.2014 - 09:14
fonte

1 risposta

9

La prima cosa da capire è che la rappresentazione binaria di 0.15625 non è 0.00101 . Sì, è quello che scriveresti se scrivessi il numero a mano. La rappresentazione effettiva del numero all'interno del computer tramite IEE 754 per la precisione singola a 32 bit. Questo è specificato come parte della specifica della lingua Java 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.

La rappresentazione binaria IEEE 754 di 0.15625 è: 0x3E200000 che può essere scomposta in:

  • un bit di segno: 0 che indica che è positivo.
  • l'esponente per i bit: 01111100 che è 124. Questo valore viene sottratto da 127 per ottenere l'esponente effettivo che verrà utilizzato ( -3 )
  • il significato e: .0100000 00000000 00000000 . Il . che ho messo lì è per la lettura in modo che sia byte, non parte del valore (il significativo utilizza i 23 bit più bassi del numero ... quindi il 24 ° bit rappresento con un . quindi l'allineamento è più facile da leggere) Questo valore è aggiunto a 1 dandoci il valore binario di 1.010.... o in base 10, 1.25000...

Combinando tutti questi elementi, otteniamo:

(- 1) 0 * 1.01 2 * 2 -3 che risulta essere, quando scritto,% codice%. Ma ricorda che abbiamo a che fare con 0.00101 .

Consente di acquisire un file sorgente Java rapido:

package com.michaelt.so.floating;

public class Demo {
    float foo = 0.15625f;
}

Il codice byte per questo, quando decompilato è:

// 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
}

Che in realtà non è troppo interessante. Puoi vedere il 0x3E200000 in là che è un caricare l'opcode costante . Prende un argomento da un pool costante e lo spinge sullo stack.

Quindi, guardiamo Demo.class con un visualizzatore di dump esadecimale.

$ 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

Guarda, proprio lì all'inizio della seconda riga ...

00000010  3e 20 00 00

C'è il numero.

Qualcuno sta per chiedere "ma perché il numero è così alto? Non c'è nemmeno un LDC 0.15625 vicino (il valore esadecimale per 12 ). ' E hanno ragione a chiedere questo. Ricorda che lo strumento LDC ha un valore dal pool costante . Il codice byte che avevo in precedenza è stato riconvertito in qualcosa che una persona potrebbe leggere.

La struttura di un file di classe può essere trovata nella specifica Java Virtual Machine sezione 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];
}

Abbiamo il numero magico in cima ( LDC ), e la versione minore ( ca fe ba be ), e la versione principale ( 00 00 = 50 10 ) e poi il conteggio del pool costante ( 00 32 ) che quindi ha il pool costante stesso.

Il pool costante è specificato nella sezione 4.4 che ha il formato:

cp_info {
    u1 tag;
    u1 info[];
}

Il valore del tag di 00 15 dice che "ciò che è prossimo è un float". Puoi vederlo alla fine della riga precedente.

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  |> ..............|

Le altre cose attorno al numero sono informazioni sulle posizioni dei metodi (ha ancora un costruttore predefinito), il nome del campo, il nome della classe, ecc ... ci sono un sacco di costanti .

Tuttavia, la cosa fondamentale è che puoi vedere il numero in virgola mobile memorizzato nel file di classe come un valore IEEE 754 che indica che questo è qualcosa che fa il compilatore.

    
risposta data 30.10.2014 - 21:04
fonte

Leggi altre domande sui tag