2 回答

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

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
- 2 回答
- 0 關注
- 164 瀏覽
添加回答
舉報