Преобразование float64 в int в Go


125

Как преобразовать float64 в int в Go? Я знаю, что strconvпакет можно использовать для преобразования чего-либо в строку или из нее, но не между типами данных, которые не являются строкой. Я знаю, что могу fmt.Sprintfпреобразовать что угодно в строку, а затем strconvв нужный мне тип данных, но это дополнительное преобразование кажется немного неуклюжим - есть ли лучший способ сделать это?


int(Round(f))чтобы установить float64 в int. См. Stackoverflow.com/a/62753031/12817546 . float64(i)чтобы установить int равным float64. См. Stackoverflow.com/a/62737936/12817546 .
Tom J

Ответы:


203
package main
import "fmt"
func main() {
  var x float64 = 5.7
  var y int = int(x)
  fmt.Println(y)  // outputs "5"
}

1
@David Grayson, Так это преобразование такое же, как Math.Floor (x) или оно теряет .7 из-за того, как float64 сохраняет его в памяти?
Дэвид Ларсен

3
@DavidLarsen Из спецификации Go: «При преобразовании числа с плавающей запятой в целое число отбрасывается (усечение до нуля)». ( Go spec )
kvu787

3
У таких преобразований есть проблема в Go, которая может быть неожиданной (по крайней мере, если вы пришли из Java): «Во всех непостоянных преобразованиях с использованием значений с плавающей запятой или комплексных значений, если тип результата не может представлять значение, преобразование выполняется успешно, но результат значение зависит от реализации ". ( golang.org/ref/spec#Conversions ). Поэтому, если вы эффективно используете очень большое значение как бесконечность и конвертируете его в int, результат не определен (в отличие от Java, где это максимальное значение целочисленного типа).
Jaan

12

Простое приведение к int обрезает число с плавающей запятой, и если ваша система внутренне представляет 2.0 как 1.9999999999, вы не получите того, чего ожидаете. Различные преобразования printf справляются с этим и правильно округляют число при преобразовании. Таким образом, чтобы получить более точное значение, преобразование еще более сложное, чем вы могли сначала ожидать:

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

Код на игровой площадке Go


8

Если это просто от float64 до int, это должно работать

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

Выходы:

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

Вот код на детской площадке - https://play.golang.org/p/HmFfM6Grqh


В Go есть функция Round, которую можно использовать для округления до ближайшего целого числа: math.Round (-64,99) выведет -65.
AHonarmand

2

Вы можете использовать int()функцию для преобразования float64данных типа в формат int. Точно так же вы можете использоватьfloat64()

Пример:

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
} 

2

Вероятно, потребуется правильное округление.

Поэтому math.Round () - ваш быстрый (!) Друг. Подходы с fmt.Sprintf и strconv.Atois () были на 2 порядка медленнее согласно моим тестам с матрицей значений float64, которые должны были стать правильно округленными значениями 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 () возвращает значение float64, но после применения int () я пока не смог найти никаких несоответствий.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.