IEEE 754二进制浮点数不精确 [英] IEEE 754 binary floating-point numbers imprecise for money

查看:73
本文介绍了IEEE 754二进制浮点数不精确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我将 math.Floor 与浮点变量一起使用时(将精度部分向下舍入/截断),我遇到了问题.我该怎么做呢?

 程序包主要进口 ("fmt"数学")func main(){var st float64 = 1980var salePrice1 = st * 0.1/1.1fmt.Printf(%T:%v \ n",salePrice1,salePrice1)//179.9999var salePrice2 = math.Floor(st * 0.1/1.1)fmt.Printf(%T:%v \ n",salePrice2,salePrice2)//179} 

游乐场: https://play.golang.org/p/49TjJwwEdEJ

输出:

  float64:179.99999999999997浮动64:179 

我希望 1980 * 0.1/1.1 的输出为 180 ,但实际输出为 179 .

解决方案

原始问题:


golang的楼层号不正确

在将Math.Floor与float变量一起使用时,我遇到问题(舍入降低/截断精度部分).我该怎么做呢?

 程序包主要进口 ("fmt"数学")func main(){var st float64 = 1980var salePrice1 = st * 0.1/1.1fmt.Printf(%T:%v \ n",salePrice1,salePrice1)var salePrice2 = math.Floor(st * 0.1/1.1)fmt.Printf(%T:%v \ n",salePrice2,salePrice2)} 

我希望1980 * 0.1/1.1的输出为180,但实际输出是179."

游乐场:

输出:

  float64:179.99999999999997浮动64:179 


XY问题是在询问您尝试的解决方案,而不是实际问题: XY问题.

>

很明显,这是 salePrice1 的货币计算.货币计算使用精确的十进制计算,而不是不精确的二进制浮点计算.

对于货币计算,请使用整数.例如,

 程序包主要导入"fmt"func main(){var st int64 = 198000//$ 1980.00作为美分fmt.Printf(%[1] T:%[1] v \ n",st)fmt.Printf("$%d.%02d \ n",st/100,st%100)var n,d int64 = 1,11fmt.Printf(%d,%d \ n",n,d)var salePrice1 int64 =(st * n)/d//向下取整fmt.Printf(%[1] T:%[1] v \ n",salePrice1)fmt.Printf("$%d.%02d \ n",salePrice1/100,salePrice1%100)var salePrice2 int64 =((st * n)* 10/d + 5)/10//四舍五入fmt.Printf(%[1] T:%[1] v \ n",salePrice2)fmt.Printf("$%d.%02d \ n",salePrice2/100,salePrice2%100)var salePrice3 int64 =(st * n +(d-1))/d//向上舍入fmt.Printf(%[1] T:%[1] v \ n",salePrice1)fmt.Printf("$%d.%02d \ n",salePrice3/100,salePrice3%100)} 

游乐场: https://play.golang.org/p/HbqVJUXXR-N

输出:

  int64:198000$ 1980.001、11int64:18000$ 180.00int64:18000$ 180.00int64:18000$ 180.00 


参考文献:

每个计算机科学家应了解的浮点运算法则

我们应如何计算货币(十进制,大浮点数)

常规十进制算术

I have a problem when I use math.Floor with a floating-point variable (round down/truncate the precision part). How can I do it correctly?

package main

import (
    "fmt"
    "math"
)

func main() {
    var st float64 = 1980
    var salePrice1 = st * 0.1 / 1.1
    fmt.Printf("%T:%v\n", salePrice1, salePrice1) // 179.9999
    var salePrice2 = math.Floor(st * 0.1 / 1.1)
    fmt.Printf("%T:%v\n", salePrice2, salePrice2) // 179
}

Playground: https://play.golang.org/p/49TjJwwEdEJ

Output:

float64:179.99999999999997
float64:179

I expect the output of 1980 * 0.1 / 1.1 to be 180, but the actual output is 179.

解决方案

The original question:


Incorrect floor number in golang

I have problem when use Math.Floor with float variable (round down/truncate the precision part). How can i do it correctly?

package main

import (
    "fmt"
    "math"
)

func main() {
    var st float64 = 1980
    var salePrice1 = st * 0.1 / 1.1
    fmt.Printf("%T:%v\n", salePrice1, salePrice1)
    var salePrice2 = math.Floor(st * 0.1 / 1.1)
    fmt.Printf("%T:%v\n", salePrice2, salePrice2)
}

I expect the output of 1980 * 0.1 / 1.1 to be 180, but the actual output is 179."

Playground:

Output:

float64:179.99999999999997
float64:179


The XY problem is asking about your attempted solution rather than your actual problem: The XY Problem.


Clearly, this is a money calculation for salePrice1. Money calculations use precise decimal calculations, not imprecise binary floating-point calculations.

For money calculations use integers. For example,

package main

import "fmt"

func main() {
    var st int64 = 198000 // $1980.00 as cents

    fmt.Printf("%[1]T:%[1]v\n", st)
    fmt.Printf("$%d.%02d\n", st/100, st%100)

    var n, d int64 = 1, 11
    fmt.Printf("%d, %d\n", n, d)

    var salePrice1 int64 = (st * n) / d // round down

    fmt.Printf("%[1]T:%[1]v\n", salePrice1)
    fmt.Printf("$%d.%02d\n", salePrice1/100, salePrice1%100)

    var salePrice2 int64 = ((st*n)*10/d + 5) / 10 // round half up

    fmt.Printf("%[1]T:%[1]v\n", salePrice2)
    fmt.Printf("$%d.%02d\n", salePrice2/100, salePrice2%100)

    var salePrice3 int64 = (st*n + (d - 1)) / d // round up

    fmt.Printf("%[1]T:%[1]v\n", salePrice1)
    fmt.Printf("$%d.%02d\n", salePrice3/100, salePrice3%100)
}

Playground: https://play.golang.org/p/HbqVJUXXR-N

Output:

int64:198000
$1980.00
1, 11
int64:18000
$180.00
int64:18000
$180.00
int64:18000
$180.00


References:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

How should we calc money (decimal, big.Float)

General Decimal Arithmetic

这篇关于IEEE 754二进制浮点数不精确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆