Convierta un float64 en un int en Go

124

¿Cómo se convierte un float64 en un int en Go? Sé que el strconvpaquete se puede usar para convertir cualquier cosa hacia o desde una cadena, pero no entre tipos de datos donde uno no es una cadena. Sé que puedo usar fmt.Sprintfpara convertir cualquier cosa en una cadena y luego strconval tipo de datos que necesito, pero esta conversión adicional parece un poco torpe, ¿hay una mejor manera de hacer esto?

Chris Bunch
fuente
int(Round(f))para establecer un float64 en un int. Consulte stackoverflow.com/a/62753031/12817546 . float64(i)para establecer un int en un float64. Consulte stackoverflow.com/a/62737936/12817546 .
Tom J

Respuestas:

202
package main
import "fmt"
func main() {
  var x float64 = 5.7
  var y int = int(x)
  fmt.Println(y)  // outputs "5"
}
David Grayson
fuente
1
@David Grayson, Entonces, ¿esta conversión es lo mismo que Math.Floor (x) o deja caer el .7 debido a la forma en que float64 lo guarda en la memoria?
David Larsen
3
@DavidLarsen From the Go spec: "Al convertir un número de punto flotante en un entero, la fracción se descarta (truncamiento hacia cero)". ( Ir a especificaciones )
kvu787
3
Tales conversiones tienen un problema en Go que puede ser inesperado (al menos si viene de Java): "En todas las conversiones no constantes que involucran valores de punto flotante o complejos, si el tipo de resultado no puede representar el valor, la conversión tiene éxito pero el resultado el valor depende de la implementación ". ( golang.org/ref/spec#Conversions ). Entonces, si usa un valor muy grande efectivamente como un infinito y lo convierte en un int, el resultado no está definido (a diferencia de Java, donde es el valor máximo del tipo entero).
Jaan
12

Simplemente convertir a un int trunca el flotante, que si su sistema representa internamente 2.0 como 1.9999999999, no obtendrá lo que espera. Las diversas conversiones de printf tratan con esto y redondean adecuadamente el número al convertir. Entonces, para obtener un valor más preciso, la conversión es aún más complicada de lo que podría esperar al principio:

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

Código en Go Playground

David Dooling
fuente
8

Si es simplemente de float64 a int, esto debería 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)
}

Salidas:

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

Aquí está el código en el patio de recreo: https://play.golang.org/p/HmFfM6Grqh

Miseria
fuente
Go tiene una función Round que puede usar y que redondea al entero más cercano: math.Round (-64.99) dará como resultado -65.
AHonarmand
2

Puede utilizar la int()función para convertir float64datos de tipo a int. Del mismo modo, puede utilizarfloat64()

Ejemplo:

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

Es probable que se desee un redondeo correcto.

Por lo tanto, math.Round () es tu amigo rápido (!). Los enfoques con fmt.Sprintf y strconv.Atois () fueron 2 órdenes de magnitud más lentos según mis pruebas con una matriz de valores float64 que estaban destinados a convertirse en valores int redondeados correctamente.

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 () devuelve un valor float64 pero con int () aplicado después, no pude encontrar ninguna discrepancia hasta ahora.

scaszoo
fuente