Ответ 1
Вам не нужен дополнительный код... его так же просто, как
import (
"fmt"
)
func main() {
k := 10 / 3.0
fmt.Printf("%.2f", k)
}
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. Есть ли другой логический метод, с помощью которого это можно сделать?
Вам не нужен дополнительный код... его так же просто, как
import (
"fmt"
)
func main() {
k := 10 / 3.0
fmt.Printf("%.2f", k)
}
Я только начинаю с 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)
Я действительно не вижу смысла, но вы можете сделать что-то вроде этого без strconv:
package main
import (
"fmt"
)
func main() {
untruncated := 10 / 3.0
truncated := float64(int(untruncated * 100)) / 100
fmt.Println(untruncated, truncated)
}
Никто не упомянул об использовании 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
.
Ответ 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
Будьте осторожны с поплавком по долготе и широте, так как усечение и округление могут дать совершенно разные результаты... так как это может поставить вас не с той стороны границы широты.
Самое простое решение - это числовое усечение (при условии, что i
- число с плавающей запятой, и вам нужна точность в 2 десятичных знака):
float64(int(i * 100)) / 100
Например:
i := 123456.789
x := float64(int(i * 100)) / 100
// x = 123456.78
Если вы имеете дело с большими числами (числами, которые могут пересекать границы максимального значения), вы должны знать, что приведенное выше может привести к серьезным проблемам с точностью с плавающей запятой:
i := float64(1<<63) // 9223372036854775808.0
fmt.Println(i, float64(int64(i * 10)) / 10)
Отпечатки: 9.223372036854776e+18 -9.223372036854776e+17
Смотрите также:
Это небольшое обходное решение, как вы можете объединить float, используя преобразование типов в int туда и обратно:
package main
import (
"fmt"
)
func main() {
k := 10 / 3.0
k = float64(int(k*100)) / 100
fmt.Println(k) // output 3.33
}
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))
}
изменить из @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)
}