亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

IEEE 754 二進制浮點數對于金錢而言不精確

IEEE 754 二進制浮點數對于金錢而言不精確

Go
鳳凰求蠱 2023-07-26 17:02:32
當我使用math.Floor浮點變量時遇到問題(向下舍入/截斷精度部分)。我怎樣才能正確地做到這一點?package mainimport (    "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}游樂場:https://play.golang.org/p/49TjJwwEdEJ輸出:float64:179.99999999999997float64:179我期望 的輸出為1980 * 0.1 / 1.1,180但實際輸出為179。
查看完整描述

2 回答

?
慕工程0101907

TA貢獻1887條經驗 獲得超5個贊

原問題:


golang中的樓層數不正確


當我將 Math.Floor 與 float 變量一起使用時遇到問題(向下舍入/截斷精度部分)。我怎樣才能正確地做到這一點?


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)

}

我預計 1980 * 0.1 / 1.1 的產量是 180,但實際產量是 179。”


操場:


輸出:


float64:179.99999999999997

float64:179

XY 問題詢問您嘗試的解決方案,而不是您的實際問題:XY 問題。


顯然,這是一個金錢計算salePrice1。貨幣計算使用精確的十進制計算,而不是不精確的二進制浮點計算。


對于貨幣計算,使用整數。例如,


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)

}

游樂場:https://play.golang.org/p/HbqVJUXXR-N


輸出:


int64:198000

$1980.00

1, 11

int64:18000

$180.00

int64:18000

$180.00

int64:18000

$180.00


查看完整回答
反對 回復 2023-07-26
?
千巷貓影

TA貢獻1829條經驗 獲得超7個贊

試試這個:


    st := 1980.0

    f := 0.1 / 1.1

    salePrice1 := st * f

    salePrice2 := math.Floor(salePrice1)

    fmt.Println(salePrice2) // 180

這是一個很大的話題:

對于會計系統:答案是浮點錯誤緩解。


(注意:一種緩解技術是使用int64、uint64、 或big.Int)


請參閱:

每個計算機科學家應該了解的浮點運算 https://en.wikipedia.org/wiki/Double- precision_floating-point_format https://en.wikipedia.org/wiki/IEEE_floating_point


讓我們從以下開始:


fmt.Println(1.0 / 3.0) // 0.3333333333333333

IEEE 754 二進制表示:


fmt.Printf("%#X\n", math.Float64bits(1.0/3.0)) // 0X3FD5555555555555

1.1 的 IEEE 754 二進制表示:


fmt.Printf("%#X\n", math.Float64bits(1.1))        // 0X3FF199999999999A

fmt.Printf("%#X\n", math.Float64bits(st*0.1/1.1)) // 0X40667FFFFFFFFFFF

現在,讓:


st := 1980.0

f := 0.1 / 1.1

IEEE 754 的二進制表示為f:


fmt.Printf("%#X\n", math.Float64bits(f)) // 0X3FB745D1745D1746

和:


salePrice1 := st * f

fmt.Println(salePrice1) // 180

fmt.Printf("%#X\n", math.Float64bits(salePrice1)) // 0X4066800000000000

salePrice2 := math.Floor(salePrice1)

fmt.Printf("%#X\n", math.Float64bits(salePrice2)) // 0X4066800000000000

在計算機上使用浮點數與使用筆和紙不同(浮點計算錯誤):


    var st float64 = 1980

    var salePrice1 = st * 0.1 / 1.1

    fmt.Println(salePrice1) // 179.99999999999997

salePrice1是 179.99999999999997 而不是 180.0,因此小于或等于 179.99999999999997 的整數值是 179:


請參閱文檔func Floor(x float64) float64:


Floor 返回小于或等于 x 的最大整數值。


看:


    fmt.Println(math.Floor(179.999))       // 179

    fmt.Println(math.Floor(179.5 + 0.5))   // 180

    fmt.Println(math.Floor(179.999 + 0.5)) // 180

    fmt.Println(math.Floor(180.0))         // 180


查看完整回答
反對 回復 2023-07-26
  • 2 回答
  • 0 關注
  • 164 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號