Floating point 如何将float64类型截断为特定精度?

Floating point 如何将float64类型截断为特定精度?,floating-point,go,Floating Point,Go,我必须编写上面的程序,以将go float64变量的精度降低到2。 在本例中,我同时使用strconv和fmt。有没有其他的逻辑方法可以做到这一点?我真的不明白这一点,但是你可以在没有strconv的情况下做到这一点: package main import ( "fmt" "strconv" ) func main() { k := 10/3.0 i := fmt.Sprintf("%.2f", k) f,_ := strconv.Parse

我必须编写上面的程序,以将go float64变量的精度降低到2。
在本例中,我同时使用strconv和fmt。有没有其他的逻辑方法可以做到这一点?

我真的不明白这一点,但是你可以在没有strconv的情况下做到这一点:

package main

import (
    "fmt"
    "strconv"
    )

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

你不需要任何额外的代码。。。简单到

package main

import (
    "fmt"
)

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

import (
    "fmt"
)

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

下面的代码应该适用于许多简单的用例,这些用例具有相对较小的数字和较小的精度输入。但是,它可能不适用于某些用例,因为数字溢出超出了float64数字的范围,以及IEEE-754舍入错误()

如果您关心使用更大的数字或需要更高的精度,以下代码可能无法满足您的需要,您应该使用帮助程序库(例如)。

我从其他地方学习了一个单行循环函数,并制作了依赖于round()的toFixed():

用法:

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
}

没有人提到使用
math/big
。与原始问题相关的结果与公认的答案相同,但如果您使用需要一定精度($money$)的浮点,则应使用
big.Float

根据原问题:

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)
不幸的是,您可以看到
.Text
没有使用定义的舍入模式(否则这个答案可能更有用),而是似乎总是向零舍入:

package main

import (
    "math/big"
    "fmt"
)

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

尽管如此,将浮点存储为大的有一定的优势。浮点

这是一个小的解决方法,如何使用类型转换来来回转换浮点:

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

// out -> 0.04

我带我来到GitHub,这里提供了一个基于
数学/big
的四舍五入值解决方案-这样就可以正确使用四舍五入方法:

package main

import (
    "fmt"
)

func main() {
    k := 10 / 3.0
    k = float64(int(k*100)) / 100
    fmt.Println(k)  // output 3.33
}
在threeve的示例中,舍入模式也受到尊重:

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)
}
->
正确生成
0.05

此外,Go 1.10已经发布并添加了一个功能,请参见icza提供的这一出色答案:

但是,不应使用
float
存储货币值。(见:)
解决这一问题的一种方法是使用实现类似或

十进制的库,小心经度和纬度浮动,因为截断和舍入可能会产生完全不同的结果。。。因为它会把你放在纬度边界的错误一边

最简单的解决方案是数值截断(假设
i
是一个浮点,并且您希望精度为2个小数点):

例如:

float64(int(i * 100)) / 100
当心! 如果您处理的是大数字(可以跨越最大值边界的数字),您应该知道上述情况可能导致:


i:=float64(1因此,经过多次搜索,我终于找到了一个非常简单的解决方案,它允许您非常简单地控制浮点的精度,而无需任何奇怪的数学运算

func FloatPrecision(num float64, precision int) float64 {
    p := math.Pow10(precision)
    value := float64(int(num*p)) / p
    return value
}
资料来源:


虽然我喜欢一些简单的方法,如
“%.3f\n”,k
选项,但这些方法会生成一个字符串,然后我必须使用另一个strconv命令将其转换回浮点值,我不想这样做。

在不检查大浮点值的情况下运行

package main

import (
    "fmt"
    "github.com/shopspring/decimal"
)

func main() {
    k := 101.3874927181298723478
    p := 5

    v := decimal.NewFromFloat(k).Round(int32(p))
    fmt.Println(v)
}
// 101.38749

为什么要降低float64变量的精度?在html中显示数据时,我不想显示或存储超过2位数字。我面临的情况是必须将其转换为字符串,因此正在考虑其他方法。仅使用fmt.Sprintf(“%.2f”,k)当你在html中显示它可能是更好的方式。我有同样的需求,但出于不同的原因。我取一个总的货币价值,并将其除以X天。我需要每天都有一个实际的货币价值,精确到一分钱,而不是一分钱的一小部分,因为我不能向我的客户收取半分钱的费用。我不想实际我需要存储一个更具体的值,因为我还需要取我的X货币值的总和,将它们加起来,然后找出与原始金额的差额,这样我就可以将差额添加到最后一天的费用中。除了下面的示例之外,数学库有
Trunc(float64)而不是使用
int()
截断FLUAT64 64 /代码>只返回整数类型,最好使用它。+ 1。固定一个小键入。这里还有一个GO播放:这不是一个相同的东西,考虑到转换为int不会圆起来。实际上,它不是圆的,它截断。如果你想围拢,你可以玩数学包。或者,你可以通过修改表达式来旋转。浮点64(整数(非整数*100+0.5))/100如果我们使用Printf,这将不起作用,只在Println中起作用。这不是舍入,而是截断。而且,只要操作的结果是要打印的,它就可以工作,但是额外的操作需要将数字解析回浮点数。Golang应该在库中真正支持舍入。我找到的最佳解决方案是使用十进制软件包。github.com/shopspring/decimal@EnmanuelRivera我想不出在什么情况下你会想要对一个四舍五入的浮点执行一个操作。我使用
math/big
添加了我的答案,它允许你在任何时候以指定的精度输出一个字符串值,同时保持“精确”浮点不变。我不明白为什么这是接受+上浮的?这不是截断,它会对数字进行取整,尽管上面有评论。例如,
fmt.Printf(“%.2f”,2.289)
会给你
2.29
(而
%f
会显示完整的
2.289
,所以这不是常数被取整的问题。)我可以证实,这是一个总结。我想这是被接受和投票的,因为它符合许多人的需要和他们所寻找的,包括我和OP,即使它不符合官方对截断的定义。可能是因为它在某些情况下会有轻微的错误答案,而实际上是错误的
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)
func FloatPrecision(num float64, precision int) float64 {
    p := math.Pow10(precision)
    value := float64(int(num*p)) / p
    return value
}
package main

import (
    "fmt"
    "github.com/shopspring/decimal"
)

func main() {
    k := 101.3874927181298723478
    p := 5

    v := decimal.NewFromFloat(k).Round(int32(p))
    fmt.Println(v)
}
// 101.38749
// Rounds like 12.3416 -> 12.35
func RoundUp(val float64, precision int) float64 {
    return math.Ceil(val*(math.Pow10(precision))) / math.Pow10(precision)
}

// Rounds like 12.3496 -> 12.34
func RoundDown(val float64, precision int) float64 {
    return math.Floor(val*(math.Pow10(precision))) / math.Pow10(precision)
}

// Rounds to nearest like 12.3456 -> 12.35
func Round(val float64, precision int) float64 {
    return math.Round(val*(math.Pow10(precision))) / math.Pow10(precision)
}