Converta um float64 em um int no Go

124

Como converter um float64 em um int no Go? Eu sei que o strconvpacote pode ser usado para converter qualquer coisa de ou para uma string, mas não entre tipos de dados onde um não é uma string. Sei que posso usar fmt.Sprintfpara converter qualquer coisa em string e depois strconvno tipo de dados de que preciso, mas essa conversão extra parece um pouco desajeitada - há uma maneira melhor de fazer isso?

Chris Bunch
fonte
int(Round(f))para definir um float64 para um int. Consulte stackoverflow.com/a/62753031/12817546 . float64(i)para definir um int para um float64. Consulte stackoverflow.com/a/62737936/12817546 .
Tom J

Respostas:

202
package main
import "fmt"
func main() {
  var x float64 = 5.7
  var y int = int(x)
  fmt.Println(y)  // outputs "5"
}
David Grayson
fonte
1
@David Grayson, então essa conversão é igual a Math.Floor (x) ou ela descarta o .7 por causa da maneira como o float64 o salva na memória?
David Larsen,
3
@DavidLarsen da especificação Go: "Ao converter um número de ponto flutuante em um inteiro, a fração é descartada (truncamento para zero)". (
Especificação de
3
Tais conversões têm um problema em Go que pode ser inesperado (pelo menos se você vier de Java): "Em todas as conversões não constantes envolvendo ponto flutuante ou valores complexos, se o tipo de resultado não pode representar o valor a conversão é bem-sucedida, mas o resultado o valor depende da implementação. " ( golang.org/ref/spec#Conversions ). Portanto, se você usar um valor muito grande efetivamente como infinito e convertê-lo em um int, o resultado é indefinido (ao contrário do Java, onde é o valor máximo do tipo inteiro).
Jaan
12

A simples conversão para um int trunca o float, que se o seu sistema internamente representar 2.0 como 1.9999999999, você não obterá o que espera. As várias conversões printf lidam com isso e arredondam adequadamente o número ao converter. Portanto, para obter um valor mais preciso, a conversão é ainda mais complicada do que você pode esperar:

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 on Go Playground

David Dooling
fonte
8

Se for simplesmente de float64 para int, isso deve funcionar

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)
}

Saídas:

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

Aqui está o código no playground - https://play.golang.org/p/HmFfM6Grqh

Amendoim
fonte
Go tem uma função Round que você pode usar para arredondar para o número inteiro mais próximo: math.Round (-64,99) resultará em -65.
AHonarmand
2

Você pode usar a int()função para converter float64dados de tipo em um int. Da mesma forma, você pode usarfloat64()

Exemplo:

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

O arredondamento correto é provavelmente desejado.

Portanto math.Round () é seu amigo rápido (!). As abordagens com fmt.Sprintf e strconv.Atois () foram 2 ordens de magnitude mais lentas de acordo com meus testes com uma matriz de valores float64 que deveriam se tornar valores int arredondados corretamente.

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 () retorna um valor float64, mas com int () aplicado posteriormente, não consegui encontrar nenhuma incompatibilidade até agora.

scaszoo
fonte