Golang précision en virgule flottante float32 vs float64

J'ai écrit un programme pour démontrer à virgule flottante d'erreur dans le jeu de Go:

func main() {
    a := float64(0.2) 
    a += 0.1
    a -= 0.3
    var i int
    for i = 0; a < 1.0; i++ {
        a += a
    }
    fmt.Printf("After %d iterations, a = %e\n", i, a)
}

Il imprime:

After 54 iterations, a = 1.000000e+00

Cela correspond au comportement d'un même programme écrit en C (à l'aide de la double type)

Toutefois, si float32 est utilisé au lieu de cela, le programme reste bloqué dans une boucle infinie! Si vous modifiez le programme C d'utiliser un float au lieu d'un double, il imprime

After 27 iterations, a = 1.600000e+00

Pourquoi ne pas le programme de Go ont le même résultat que le programme C lors de l'utilisation de float32?

  • Je ne vois pas de problème... 0.2 + 0.1 = 0.3, 0.3 - 0.3 = 0.0, boucle à travers 0.0 + 0.0 ne serait jamais s'élever au-dessus de 1,0 Ce que je suis confus sur la façon dont vous avez réussi à le faire sortir de la boucle avec la float64?
  • les nombres à virgule flottante ne sont pas parfaitement exactes. En particulier, le nombre de 0,1 et 0,3 ne peut pas être représenté exactement. Cela provoque a avoir une valeur non nulle (même très petite) valeur avant d'entrer dans la boucle. Wikipedia a une explication. en.wikipedia.org/wiki/Guard_digit
  • J'ai commencé à jouer avec cette aire de jeux play.golang.org/p/Im6OFfTFPY, et j'ai un peu de voir ce que tu veux dire, mais il semble en Aller float32s sont représentés exactement, tandis que float64s ne sont pas
  • Si vous cochez l'ASM du code avec go tool 6g -S main.go vous verrez la raison. Le calcul pour float32 est comme suit: 2.00000002980232230 e-01 + 1.00000001490116120 e-01 - 3.00000011920928950 e-01, qui est une valeur négative, et ne sera jamais la somme des 1. Pourquoi Aller à cela, je ne sais pas.
  • Joué avec une autre aire de jeux (play.golang.org/p/FZxCQTS9yG) un peu plus de temps et a constaté que lorsque vous imprimez le float64 jusqu'à 20 décimales, vous obtenez beaucoup plus de chiffres que de simplement 0.30...04, vous obtenez 0.30000000000000004440892098500626161694526672363281 et le reste est coupée. Je suppose qu'avec un float32, beaucoup plus coupée et il devient arrondi à un même 0.3. Cela pourrait expliquer l'arithmétique, mais pour l'instant c'est juste une théorie.