LoginSignup
2
1

Float型の標準出力の有効数字のデフォルトはなぜ6桁なのか

Last updated at Posted at 2024-01-31

Float型の標準出力の有効数字のデフォルトはなぜ6桁なのか

風船ガム

イチゴ味の風船ガムを食べてました。

くちゃくちゃ味わい、ふくらます。
口に広がる甘酢っぱさ。
フルーティーが鼻をつつく。

何回かそれを繰り返していると ふと
どれくらい大きくなるのだろうと
思いました。

おもいっきり息を吐き 
風船ガムをふくらませました。

ドンドン大きくなるガム。

破けることなく大きくなり
ついに私は空を飛びました。

ああ、でも残念なことに
私はずっと上を向いたまま。

下に広がる素敵な景色は見れません。

「私はどこまで浮かびつづけるのでしょうか」

浮かびながら空に聞くのでした。

目次
1. そもそもFloat型って何?
2. Float型の標準出力の例
3. なぜデフォルトは6桁なのか
4. おわりに

1. そもそもFloat型って何?

Float型とは

 float 型は、コンピュータプログラミングにおいて、数値を表現するために使用されるデータ型の一つです。

float 型の名前の由来は、その数値表現が「浮動小数点」(floating-point) 形式に基づいていることから来ています。この用語は、数値の小数点が「浮いている」(つまり、位置が固定されていない)ことを意味します。

image.png

浮動小数点とは

 浮動小数点数とは、数値を符号部、指数部、および仮数部(または分数部)の3つの要素で表現し、これによって非常に大きい数値や非常に小さい数値を効率的に表現することができます。

 IEEE 754のbinary32(単精度浮動小数点数)形式において、数値は以下のように表されます。

数値 = (-1)^符号部 * 1.仮数部 * 2^(指数部 - バイアス)

仮数部、指数部、符号部

 float 型は、32ビットのメモリを使用し、そのビットは符号部、指数部、仮数部に分けられています。

 そこで、各部分の役割とビット数の割り当て、およびその理由について説明し、テーブル形式で整理してみます。

符号部
ビット数: 1ビット

説明: 数値の符号を表します。0は正、1は負を意味します。

理由: 符号部は数値が正か負かを示す必要があるため、1ビットあれば十分です(2状態、つまり正か負を表すことができます)。


指数部
ビット数: 8ビット

説明: 数値のスケール(大きさ)を決定します。指数部は、バイアス表記を使用して表され、実際の指数値に特定の数(127)を加えた値が格納されます。

 バイアス表記は、浮動小数点数の指数を表現するための工夫された方法です。バイアス表記は、指数が正の数値も負の数値も取り得ることを考慮し、すべての指数値を非負の整数としてエンコードするために使用されます。

 バイアス表記は奥が深すぎるのでまたの機会に。

理由: 8ビットを使用することで、十分な大きさと精度の範囲を提供し、非常に小さい数値から非常に大きな数値まで表現できます。


仮数部
ビット数: 23ビット

説明: 数値の実際のデータ(数字)を保持します。これは、数値の有効数字を表し、1.xxxxの形式の数値で、先頭の1は通常省略されます(暗黙のビット)。

理由: 仮数部は数値の精度を決定します。23ビットは、数値の精度と表現できる範囲のバランスを考慮して選ばれました。32 - 1 - 8 = 23


テーブル

部分 ビット数 説明 理由
符号部 1ビット 数値の符号(正か負)を表す。 正負2状態を表現するのに1ビットあれば十分。
指数部 8ビット 数値のスケール(大きさ)を表す。 広範囲の数値を表現するために、十分な数のビットが割り当てられている。
仮数部 23ビット 数値の有効数字を表す。1.xxxx形式で、先頭の1は暗黙のビットとして省略される。 数値の精度を決定し、適切なバランスを提供するために選ばれたビット数。

2. Float型の標準出力の例

 では次に具体的な出力結果を複数の言語のコードで見て頂きます。

C言語の場合

#include <stdio.h>

int main() {
    float number = 0.1234567;
    printf("%f\n", number);
    return 0;
}

出力:

0.123457

C++の場合

#include <iostream>
#include <iomanip>

int main() {
    float number = 0.1234567;
    std::cout << number << std::endl;
    return 0;
}

出力:

0.123457

Javaの場合

public class Main {
    public static void main(String[] args) {
        float number = 0.1234567f;
        System.out.printf("%f%n", number);
    }
}

出力:

0.123457

Go言語の場合

package main

import (
    "fmt"
)

func main() {
    var number float32 = 0.1234567
    fmt.Printf("%f\n", number)
}

出力:

0.123457

3. なぜデフォルトは6桁なのか

 見て頂いてわかる通り、デフォルトだと、有効数字6桁で、7桁目は四捨五入されています。

これは先程の仮数部が関係しています。

 float 型は、仮数部に23ビットを使用し、加えて暗黙のビット(通常は1とされる)があるため、実質的には24ビットの精度を持っています。

 10進数の桁数は、2進数のビット数に対数を使って変換することができます。

 具体的には、log10(2)(約0.3010)を使って変換します。

 24ビットで表せる桁数を計算すると、以下のようになります:

24ビット * log10(2)
-> 24 * 0.3010 = 7.224

この計算により、float型が理論的には約7桁の精度を持つことを示しています。

 しかし、実際の計算で丸め誤差が生じるため、安全な有効桁数としては通常6桁が使用されます。

2進数で表現される浮動小数点数は、特に10進数で表される数値を正確に表現できない場合があります(例えば、0.1や0.2など)。

 このような数値は2進数で近似値に丸められますが、その結果として微小な誤差が発生します。

 この誤差は、計算の過程で蓄積される可能性があります。

 なのでデフォルトでは主に、6桁の有効数字が使われているのです。

4. おわりに

 floatの記事を書くにあたり、IPv4が32ビットだったり、アスキーコードの幅が8ビットだったり、数字と実用性の美しい関係に思いをはせることができ、楽しかったです。

 浮いた気持ちを落ち着かせながら……。

2
1
14

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
2
1