57
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-09-03

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

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

f1-1.PNG

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

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

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型の値の内部表現を取得することができます。

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 );
    }
}
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型の値の内部表現を取得することができます。

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型の値の内部表現を取得することができます。

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」オプションを付けてコンパイルする必要があります。

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!

57
52
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?