Подтвердить что ты не робот

Как мы можем обрезать тип float64 с определенной точностью в golang?

package main

import (
    "fmt"
    "strconv"
    )

func main() {
    k := 10/3.0
    i := fmt.Sprintf("%.2f", k)
    f,_ := strconv.ParseFloat(i, 2)
    fmt.Println(f)
}

Мне пришлось написать программу выше, чтобы уменьшить точность переменной go float64 до 2. В этом случае я использовал как strconv, так и fmt. Есть ли другой логический метод, с помощью которого это можно сделать?

4b9b3361

Ответ 1

Вам не нужен дополнительный код... его так же просто, как

import (
    "fmt"
)

func main() {
    k := 10 / 3.0
    fmt.Printf("%.2f", k)
}

Тестовый код

Ответ 2

Я только начинаю с Go и обнаружил удивительным, что у него нет функции "toFixed" (как в JavaScript), которая будет выполнять то, что вы хотите, и даже "круглую" функцию.

Я взял однолинейную круглую функцию из другого места, а также сделал toFixed(), которая зависит от round():

func round(num float64) int {
    return int(num + math.Copysign(0.5, num))
}

func toFixed(num float64, precision int) float64 {
    output := math.Pow(10, float64(precision))
    return float64(round(num * output)) / output
}

Использование:

fmt.Println(toFixed(1.2345678, 0))  // 1
fmt.Println(toFixed(1.2345678, 1))  // 1.2
fmt.Println(toFixed(1.2345678, 2))  // 1.23
fmt.Println(toFixed(1.2345678, 3))  // 1.235 (rounded up)

Ответ 3

Я действительно не вижу смысла, но вы можете сделать что-то вроде этого без strconv:

package main

import (
    "fmt"
)

func main() {
    untruncated := 10 / 3.0
    truncated := float64(int(untruncated * 100)) / 100
    fmt.Println(untruncated, truncated)
}

Ответ 4

Никто не упомянул об использовании math/big. Результаты, относящиеся к исходному вопросу, совпадают с принятым ответом, но если вы работаете с поплавками, требующими определенной точности ($ money $), вы должны использовать big.Float.

По оригинальному вопросу:

package main

import (
    "math/big"
    "fmt"
)

func main() {
    // original question
    k := 10 / 3.0
    fmt.Println(big.NewFloat(k).Text('f', 2))
}

К сожалению, вы можете видеть, что .Text не использует определенный режим округления (иначе этот ответ может быть более полезным), но, скорее, он всегда округляется до нуля:

j := 0.045
fmt.Println(big.NewFloat(j).SetMode(big.AwayFromZero).Text('f', 2)

// out -> 0.04

Тем не менее, есть некоторые преимущества, связанные с тем, что ваш поплавок хранится как big.Float.

Ответ 5

Ответ Threeve привел меня к этой проблеме на GitHub, где представлено решение, основанное на math/big значениях для округления - таким образом, метод округления используется правильно:

package main

import (
    "fmt"
    "math/big"
)

func main() {
    f := new(big.Float).SetMode(big.ToNearestEven).SetFloat64(10/3.0)
    // Round to 2 digits using formatting.
    f.SetPrec(8)
    fmt.Printf("%.2f\n", f)
}

Режим округления также соблюдается в трех примерах:

j := 0.045

f := new(big.Float).SetMode(big.AwayFromZero).SetFloat64(j)
// Round to 2 digits using formatting.
f.SetPrec(8)
fmt.Printf("%.2f\n", f)

-> правильно дает 0.05

Кроме того, Go 1.10 был выпущен и добавил функцию math.Round(), см. Этот превосходный ответ от icza: Golang Round to Nearest 0.05

package main

import (
    "fmt"
    "math"
)

func main() {

    fmt.Println(Round(10/3.0, 0.01))

}

func Round(x, unit float64) float64 {
    return math.Round(x/unit) * unit
}

Однако не следует использовать float для хранения денежных значений. (См.: Почему бы не использовать Double или Float для представления валюты?) Одним из способов решения этой проблемы является использование библиотеки, которая реализует decimal такие как https://github.com/ericlagergren/decimal или https://github.com/shopspring/decimal

Ответ 6

Будьте осторожны с поплавком по долготе и широте, так как усечение и округление могут дать совершенно разные результаты... так как это может поставить вас не с той стороны границы широты.

Ответ 7

Самое простое решение - это числовое усечение (при условии, что i - число с плавающей запятой, и вам нужна точность в 2 десятичных знака):

float64(int(i * 100)) / 100

Например:

i := 123456.789
x := float64(int(i * 100)) / 100
// x = 123456.78

BEWARE!

Если вы имеете дело с большими числами (числами, которые могут пересекать границы максимального значения), вы должны знать, что приведенное выше может привести к серьезным проблемам с точностью с плавающей запятой:

i := float64(1<<63) // 9223372036854775808.0
fmt.Println(i, float64(int64(i * 10)) / 10)

Отпечатки: 9.223372036854776e+18 -9.223372036854776e+17

Смотрите также:

  1. как работают 32-битные числа с плавающей точкой
  2. как работают 64-битные числа с плавающей точкой
  3. константы диапазона числовых значений math Голанга
  4. Голанг math/big

Ответ 8

Это небольшое обходное решение, как вы можете объединить float, используя преобразование типов в int туда и обратно:

package main

import (
    "fmt"
)

func main() {
    k := 10 / 3.0
    k = float64(int(k*100)) / 100
    fmt.Println(k)  // output 3.33
}

https://play.golang.org/p/yg2QYcZ-2u

Ответ 9

package main

import (
    "fmt"
    "math"
)
func main() {
    fmt.Println(round(0.050000000700000005, 8))
}

func round(val float64, prec int) float64 {

    rounder := math.Floor(val * math.Pow(10, float64(prec)))

    return rounder / math.Pow(10, float64(prec))
}

Ответ 10

изменить из @creack

package main

import (
    "fmt"
)

func main() {

    //untruncated := 10/3.0
    untruncated := 4.565
    tmp := int(untruncated*100)
    last := int(untruncated*1000)-tmp*10
    if last>=5{
        tmp += 1
    }
    truncated := float64(tmp)/100

    fmt.Println(untruncated, truncated)
}