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

1を1億回足して1億にならない場合

More than 3 years have passed since last update.

まぁ浮動小数点型の仕様を知れば当たり前の話なのだが,面白そうなので「1を1億回足す」ってのを Go 言語でも書いてみる。

loop1.go
package main

import "fmt"

func main() {
    var d float32 = 0.0
    for i := 0; i < 100000000; i++ {
        d += 1.0
    }
    fmt.Println(d)
}

実行結果は予想通り

$ go run loop1.go
1.6777216e+07

となる1。念のため float64 でも試してみよう。

loop2.go
package main

import "fmt"

func main() {
    var d float64 = 0.0
    for i := 0; i < 100000000; i++ {
        d += 1.0
    }
    fmt.Println(d)
}

結果は

$ go run loop2.go
1e+08

で,ちゃんと1億になる。 Go 言語では基本型のサイズが厳密に決まってるので,浮動小数点型の計算誤差についてもきちんと見積もれるはずである。

ちなみに

loop3.go
package main

import "fmt"

func main() {
    for d := 0.0; d < 1.0; d += 0.1 {
        fmt.Println(d)
    }
}

とすると2

$ go run loop3.go
0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999

ってなことになる3 ので浮動小数点型の変数をループカウンタにするのは止めましょうね。約束だよ!

ブックマーク



  1. float32 は32ビットサイズの浮動小数点数型で,符号部1ビット,指数部8ビット,仮数部23ビット,という内訳になっている(仮数部は仮数の小数点以下を表す)。つまり有効桁数が24ビット(10進数で約7桁)しかない。したがって今回のような「1づつ加算する動作を繰り返す」処理では16,777,216(=0xffffff+1)以降は「情報落ち」が発生する。ちなみに float64 は64ビットサイズで仮数部は52ビットあり,10進数にして約15桁の有効桁数になる。 

  2. d := 0.0” と記述した場合,変数 dfloat64 として宣言・初期化される。厳密には定数 “0.0” は,いったん「型付けなし」の浮動小数点数として評価された後,変数宣言時に float64 に暗黙的に変換される。 Go 言語におけるこの定数の機能は何かと便利なので覚えておくとよいだろう。 

  3. このような結果になるのは float32/float64 の浮動小数点数型の内部表現が2進数になっているため。たとえば 0.1 を2進数で表すと「0.000110011...」と循環しキリのいい値にならない。このため 0.1 を加算していくと「丸め誤差」が蓄積していくのである。 

Why not register and get more from Qiita?
  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
No 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
ユーザーは見つかりませんでした