浮動小数点数の内部表現を取得してみよう

ニアです、こんにちはー！
今回は浮動小数点数の内部表現を取得する方法を紹介していきます。

#1. 浮動小数点数とは
浮動小数点数とは符号部、指数部、仮数部で小数を表現した数です。多くのプログラミング言語では、IEEE 754という標準規格が採用されていまり、内部表現で上位から符号部、指数部、仮数部の順に並んでいます。

![f1-1.PNG](https://qiita-image-store.s3.amazonaws.com/0/78881/623c5ff3-9606-4486-4af7-19079b021ba2.png)



#2. プログラムで浮動小数点数の内部表現を取得してみよう
ここでは、単精度浮動小数点型（float型）の内部表現を取得するプログラムをいくつか作成していきます。言語はC、C++、C#、VB.NET、Javaです。

##2.1 共用体を利用した方法（ C言語、C++ ）
C言語、C++では、**float型変数1つ**とfloat型とデータサイズが同じである**int型変数1つ**で構成した**共用体**を利用します。共用体の各メンバーは同じメモリ領域にいるので、float型のメンバーに実数を入れると、int型のメンバーからfloat型の値の内部表現を取得することができます。


```c:float-bin.c
#include <stdio.h>

int main( void ) {

    /* float型のデータサイズは32ビットなので、32ビット整数型（ int ）とコンビを組みます */
    union { float f; int i; } a;
    int i;
    a.f = -2.5f;

    printf( "%f ( %08X )\n", a.f, a.i );
    
    /* ビットの列を表示します */
    for( i = 31; i >= 0; i-- ){
        printf( "%d", ( a.i >> i ) & 1 );
    }
    printf( "\n" );
    
    /* 指数部（ 1ビット ）、指数部（ 8ビット ）、仮数部（ 23ビット ）を取り出します */
    printf( "符号部 : %X\n", ( a.i >> 31 ) & 1 );
    printf( "指数部 : %X\n", ( a.i >> 23 ) & 0xFF );
    printf( "仮数部 : %X\n", a.i & 0x7FFFFF );

    return 0;
}
```

> **実行結果**
-2.500000 ( C0200000 )
11000000001000000000000000000000
符号部 : 1
指数部 : 80
仮数部 : 200000

※C++でも動作します。

##2.2 クラスの機能を利用した方法（ C#、VB.NET、Java ）
C#とVB.NETでは、.NET Frameworkの**BitConverterクラス**を利用します。**BitConverter.GetBytes**メソッドでfloat型の値を一旦、byte型配列に変換し、そこから**BitConverter.ToInt32**メソッドでfloat型の値の内部表現を取得することができます。

```csharp:float-bin.cs
using System;

public class Program{
    public static void Main(){
        
        float f = -2.5f;
        // BitConverter.ToInt32メソッドは、byte配列と変換対象の最初のインデックスを引数にとります
        int i = BitConverter.ToInt32( BitConverter.GetBytes( f ), 0 );
        Console.WriteLine( "{0:F} ( {1:X8} )", f, i );
        
        // ビットの列を表示します
        for( int j = 31; j >= 0; j-- ){
            Console.Write( ( i >> j ) & 1 );
        }
        Console.WriteLine();
        
        // 指数部（ 1ビット ）、指数部（ 8ビット ）、仮数部（ 23ビット ）を取り出します
        Console.WriteLine( "符号部 : {0:X}", ( i >> 31 ) & 1 );
        Console.WriteLine( "指数部 : {0:X}", ( i >> 23 ) & 0xFF );
        Console.WriteLine( "仮数部 : {0:X}", i & 0x7FFFFF );
    }
}
```

```vbnet:float-bin.vb
Module Module1

    Sub Main()
		
	Dim f As Single = -2.5f
        ' BitConverter.ToInt32メソッドは、byte配列と変換対象の最初のインデックスを引数にとります
        Dim i As Integer = BitConverter.ToInt32( BitConverter.GetBytes( f ), 0 )
        Console.WriteLine( "{0:F} ( {1:X8} )", f, i )
        
        ' ビットの列を表示します
        Dim j As Integer
        For j = 31 To 0 Step -1
            Console.Write( ( i >> j ) And 1 )
        Next
        Console.WriteLine()
        
        ' 指数部（ 1ビット ）、指数部（ 8ビット ）、仮数部（ 23ビット ）を取り出します
        Console.WriteLine( "符号部 : {0:X}", ( i >> 31 ) And 1 )
        Console.WriteLine( "指数部 : {0:X}", ( i >> 23 ) And &HFF )
        Console.WriteLine( "仮数部 : {0:X}", i And &H7FFFFF )

        
    End Sub

End Module
```


Javaでは、**Floatクラス**を利用します。**Float.floatToIntBits**メソッドでfloat型の値の内部表現を取得することができます。

```java:float-bin.java
public class Main {
    public static void main(String[] args) throws Exception {
        
        float f = -2.5f;
        int i = Float.floatToIntBits( f );
        System.out.printf( "%f ( %08X )\n", f, i );
        
        // ビットの列を表示します
        for( int j = 31; j >= 0; j-- ){
            System.out.printf( "%d", ( i >> j ) & 1 );
        }
        System.out.println();
        
        // 指数部（ 1ビット ）、指数部（ 8ビット ）、仮数部（ 23ビット ）を取り出します
        System.out.printf( "符号部 : %X\n", ( i >> 31 ) & 1 );
        System.out.printf( "指数部 : %X\n", ( i >> 23 ) & 0xFF );
        System.out.printf( "仮数部 : %X\n", i & 0x7FFFFF );
        
    }
}
```


##2.3 ポインタのキャスト変換を利用した方法（ C言語、C++、C# ）
C言語、C++、C#では、**float型のポインタをint型のポインタにキャスト変換する**ことで、float型の値の内部表現を取得することができます。

```c:float-binptr.c
#include <stdio.h>

int main( void ) {

    float f = -2.5f;
    int i = *( ( int* )&f ), j;
    printf( "%f ( %08X )\n", f, i );
    
    /* ビットの列を表示します */
    for( j = 31; j >= 0; j-- ){
        printf( "%d", ( i >> j ) & 1 );
    }
    printf( "\n" );
    
    /* 指数部（ 1ビット ）、指数部（ 8ビット ）、仮数部（ 23ビット ）を取り出します */
    printf( "符号部 : %X\n", ( i >> 31 ) & 1 );
    printf( "指数部 : %X\n", ( i >> 23 ) & 0xFF );
    printf( "仮数部 : %X\n", i & 0x7FFFFF );

    return 0;
}
```

※C++でも動作します。

C#の場合、ポインタはアンセーフコードとして扱うので、「**/unsafe**」オプションを付けてコンパイルする必要があります。

```csharp:float-binptr.cs
using System;

public class Program {
	// アンセーフコードを扱う時は、「unsafe」キーワードを付けます。
	public unsafe static void Main() {

		float f = -2.5f;
		int i = *( ( int* )&f );
		Console.WriteLine( "{0:F} ( {1:X8} )", f, i );

		// ビットの列を表示します
		for( int j = 31; j >= 0; j-- ) {
			Console.Write( ( i >> j ) & 1 );
		}
		Console.WriteLine();

		// 指数部（ 1ビット ）、指数部（ 8ビット ）、仮数部（ 23ビット ）を取り出します
		Console.WriteLine( "符号部 : {0:X}", ( i >> 31 ) & 1 );
		Console.WriteLine( "指数部 : {0:X}", ( i >> 23 ) & 0xFF );
		Console.WriteLine( "仮数部 : {0:X}", i & 0x7FFFFF );
	}
}
```

#3. おわりに
今回はいくつかの言語を例に、float型の内部表現を取得するプログラムを作成しました。もちろん、double型でも同じような方法で内部表現を取得することができます。

例えば、コンピュータの授業で浮動小数点数の計算の様子を見る時に活用してみてはいかがでしょう。

それでは、See you next time!