Konwertuj float64 na int w Go

124

Jak przekonwertować float64 na int w Go? Wiem, że strconvpakiet może służyć do konwertowania czegokolwiek na lub z ciągu, ale nie między typami danych, w których jeden nie jest ciągiem. Wiem, że mogę użyć fmt.Sprintfdo przekonwertowania czegokolwiek na ciąg, a następnie strconvna typ danych, którego potrzebuję, ale ta dodatkowa konwersja wydaje się nieco niezdarna - czy jest lepszy sposób na zrobienie tego?

Chris Bunch
źródło
int(Round(f))aby ustawić float64 na int. Zobacz stackoverflow.com/a/62753031/12817546 . float64(i)aby ustawić int na float64. Zobacz stackoverflow.com/a/62737936/12817546 .
Tom J

Odpowiedzi:

202
package main
import "fmt"
func main() {
  var x float64 = 5.7
  var y int = int(x)
  fmt.Println(y)  // outputs "5"
}
David Grayson
źródło
1
@David Grayson, Czy więc ta konwersja jest taka sama, jak Math.Floor (x), czy też upuszcza .7 ze względu na sposób, w jaki float64 zapisuje go w pamięci?
David Larsen
3
@DavidLarsen Ze specyfikacji Go: "Podczas konwersji liczby zmiennoprzecinkowej na liczbę całkowitą ułamek jest odrzucany (obcięcie w kierunku zera)". ( Idź do specyfikacji )
kvu787
3
Takie rzutowania mają problem w Go, który może być nieoczekiwany (przynajmniej jeśli pochodzisz z Javy): „We wszystkich niestandardowych konwersjach obejmujących wartości zmiennoprzecinkowe lub zespolone, jeśli typ wyniku nie może reprezentować wartości, konwersja się powiedzie, ale wynik wartość zależy od implementacji ”. ( golang.org/ref/spec#Conversions ). Więc jeśli efektywnie użyjesz bardzo dużej wartości jako nieskończoności i przekonwertujesz ją na int, wynik jest niezdefiniowany (w przeciwieństwie do Java, gdzie jest to maksymalna wartość typu całkowitego).
Jaan
12

Zwykłe rzutowanie na int obcina liczbę zmiennoprzecinkową, która jeśli Twój system wewnętrznie reprezentuje 2.0 jako 1.9999999999, nie uzyskasz tego, czego oczekujesz. Różne konwersje printf radzą sobie z tym i odpowiednio zaokrąglają liczbę podczas konwersji. Aby uzyskać dokładniejszą wartość, konwersja jest jeszcze bardziej skomplikowana, niż można by się było spodziewać:

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
źródło
8

Jeśli to po prostu od float64 do int, to powinno działać

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

Wyjścia:

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

Oto kod na placu zabaw - https://play.golang.org/p/HmFfM6Grqh

Orzeszki ziemne
źródło
Go ma funkcję Round, której możesz użyć, która zaokrągla do najbliższej liczby całkowitej: math.Round (-64,99) daje wynik -65.
AHonarmand
2

Możesz użyć int()funkcji, aby przekonwertować float64dane typu na plik int. Podobnie możesz użyćfloat64()

Przykład:

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
źródło
2

Prawdopodobnie pożądane jest prawidłowe zaokrąglenie.

Dlatego math.Round () jest twoim szybkim (!) Przyjacielem. Podejścia z fmt.Sprintf i strconv.Atois () były o 2 rzędy wielkości wolniejsze, zgodnie z moimi testami z macierzą wartości float64, które miały stać się poprawnie zaokrąglonymi wartościami int.

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 () zwraca wartość float64, ale po zastosowaniu funkcji int () nie mogłem do tej pory znaleźć żadnych niezgodności.

scaszoo
źródło