Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

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!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away