Convertir un float64 en un int dans Go

125

Comment convertir un float64 en int dans Go? Je sais que le strconvpackage peut être utilisé pour convertir n'importe quoi vers ou à partir d'une chaîne, mais pas entre des types de données où l'on n'est pas une chaîne. Je sais que je peux utiliser fmt.Sprintfpour convertir n'importe quoi en chaîne, puis strconvle type de données dont j'ai besoin, mais cette conversion supplémentaire semble un peu maladroite - y a-t-il une meilleure façon de le faire?

Chris Bunch
la source
int(Round(f))pour définir un float64 sur un int. Voir stackoverflow.com/a/62753031/12817546 . float64(i)pour définir un int sur un float64. Voir stackoverflow.com/a/62737936/12817546 .
Tom J

Réponses:

203
package main
import "fmt"
func main() {
  var x float64 = 5.7
  var y int = int(x)
  fmt.Println(y)  // outputs "5"
}
David Grayson
la source
1
@David Grayson, Cette conversion est-elle donc la même que Math.Floor (x) ou supprime-t-elle le .7 à cause de la façon dont le float64 l'enregistre en mémoire?
David Larsen
3
@DavidLarsen De la spécification Go: "Lors de la conversion d'un nombre à virgule flottante en entier, la fraction est supprimée (troncature vers zéro)". ( Go spec )
kvu787
3
Ces transtypages ont un problème dans Go qui peut être inattendu (du moins si vous venez de Java): "Dans toutes les conversions non constantes impliquant des valeurs à virgule flottante ou complexes, si le type de résultat ne peut pas représenter la valeur, la conversion réussit mais le résultat la valeur dépend de la mise en œuvre. " ( golang.org/ref/spec#Conversions ). Donc, si vous utilisez efficacement une très grande valeur comme infini, et que vous la convertissez en un entier, le résultat n'est pas défini (contrairement à Java, où il s'agit de la valeur maximale du type entier).
Jaan
12

Le simple cast en int tronque le flottant, ce qui, si votre système représente en interne 2.0 comme 1.9999999999, vous n'obtiendrez pas ce que vous attendez. Les différentes conversions printf traitent de cela et arrondissent correctement le nombre lors de la conversion. Donc, pour obtenir une valeur plus précise, la conversion est encore plus compliquée que ce à quoi vous pourriez vous attendre:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    floats := []float64{1.9999, 2.0001, 2.0}
    for _, f := range floats {
        t := int(f)
        s := fmt.Sprintf("%.0f", f)
        if i, err := strconv.Atoi(s); err == nil {
            fmt.Println(f, t, i)
        } else {
            fmt.Println(f, t, err)
        }
    }
}

Code sur Go Playground

David Dooling
la source
8

Si c'est simplement de float64 à int, cela devrait fonctionner

package main

import (
    "fmt"
)

func main() {
    nf := []float64{-1.9999, -2.0001, -2.0, 0, 1.9999, 2.0001, 2.0}

    //round
    fmt.Printf("Round : ")
    for _, f := range nf {
        fmt.Printf("%d ", round(f))
    }
    fmt.Printf("\n")

    //rounddown ie. math.floor
    fmt.Printf("RoundD: ")
    for _, f := range nf {
        fmt.Printf("%d ", roundD(f))
    }
    fmt.Printf("\n")

    //roundup ie. math.ceil
    fmt.Printf("RoundU: ")
    for _, f := range nf {
        fmt.Printf("%d ", roundU(f)) 
    }
    fmt.Printf("\n")

}

func roundU(val float64) int {
    if val > 0 { return int(val+1.0) }
    return int(val)
}

func roundD(val float64) int {
    if val < 0 { return int(val-1.0) }
    return int(val)
}

func round(val float64) int {
    if val < 0 { return int(val-0.5) }
    return int(val+0.5)
}

Les sorties:

Round : -2 -2 -2 0 2 2 2 
RoundD: -2 -3 -3 0 1 2 2 
RoundU: -1 -2 -2 0 2 3 3 

Voici le code dans la cour de récréation - https://play.golang.org/p/HmFfM6Grqh

Cacahuètes
la source
Go a une fonction Round que vous pouvez utiliser qui arrondit à l'entier le plus proche: math.Round (-64,99) produira -65.
AHonarmand
2

Vous pouvez utiliser la int()fonction pour convertir float64les données de type en fichier int. De même, vous pouvez utiliserfloat64()

Exemple:

func check(n int) bool { 
    // count the number of digits 
    var l int = countDigit(n)
    var dup int = n 
    var sum int = 0 

    // calculates the sum of digits 
    // raised to power 
    for dup > 0 { 
        **sum += int(math.Pow(float64(dup % 10), float64(l)))** 
        dup /= 10 
    } 

    return n == sum
} 
Codemaker
la source
2

Un arrondi correct est probablement souhaité.

Par conséquent, math.Round () est votre ami rapide (!). Les approches avec fmt.Sprintf et strconv.Atois () étaient 2 ordres de grandeur plus lentes selon mes tests avec une matrice de valeurs float64 qui étaient destinées à devenir des valeurs int correctement arrondies.

package main
import (
    "fmt"
    "math"
)
func main() {
    var x float64 = 5.51
    var y float64 = 5.50
    var z float64 = 5.49
    fmt.Println(int(math.Round(x)))  // outputs "6"
    fmt.Println(int(math.Round(y)))  // outputs "6"
    fmt.Println(int(math.Round(z)))  // outputs "5"
}

math.Round () renvoie une valeur float64 mais avec int () appliqué par la suite, je n'ai pas pu trouver de discordance jusqu'à présent.

scaszoo
la source