英文:
GoLang for loop with floats creates error
问题
有人能解释一下吗?我在Go语言中有一个函数,它接受一对float64类型的参数,然后使用这些值计算出许多其他值。函数的定义如下:
func (g *Geometry) CalcStresses(x, zmax, zmin float64) (Vertical)
计算结果被放入一个结构体中,如下所示:
type Vertical struct {
X float64
Stresses []Stress
}
现在有个有趣的问题。如果我像这样调用函数:
for i := 14.0; i < 15.0; i += 0.1 {
result := geo.CalcStresses(i, 10, -10)
}
那么我会得到很多结果,其中Stress数组是空的。另一个有趣的细节是,x有时会显示为一个带有很多小数位的数字(例如14.3999999999999999998)。
然而,如果我像这样调用函数:
for i := 0; i < 10; i++ {
x := 14.0 + float64(i)*0.1
result := geo.CalcStresses(x, 10, -10)
}
那么一切都正常。
有人知道为什么会出现这种情况吗?
提前感谢,
Rob
英文:
Can someone explain the following. I have a function in go that accepts a couple of float64 and then uses this value to calculate a lot of other values. The function looks like
func (g *Geometry) CalcStresses(x, zmax, zmin float64)(Vertical)
the result is put into a struct like
type Vertical struct {
X float64
Stresses []Stress
}
Now the funny thing is this. If I call the function like this;
for i:=14.0; i<15.0; i+=0.1{
result := geo.CalcStresses(i, 10, -10)
}
then I get a lot of results where the Stress array is empty, antoher interesting detail is that x sometimes shows like a number with a LOT of decimals (like 14.3999999999999999998)
However, if I call the function like this;
for i:=0; i<10; i++{
x := 14.0 + float64(i) * 0.1
result := geo.CalcStresses(x,10,-10)
}
then everything is fine.
Does anyone know why this happens?
Thanks in advance,
Rob
答案1
得分: 6
并不是所有的实数都可以在二进制浮点格式中精确表示,因此在浮点数上进行循环可能会引发问题。
根据维基百科上的浮点数条目:
浮点数不能精确表示所有实数,浮点运算也不能精确表示真正的算术运算,这导致了许多令人惊讶的情况。这与计算机通常以有限精度表示数字有关。
例如,0.1和0.01(在二进制中)无法表示,这意味着尝试对0.1进行平方的结果既不是0.01,也不是最接近它的可表示数字。
这段代码:
for i := 14.0; i < 15.0; i += 0.1 {
fmt.Println(i)
}
产生以下输出:
14
14.1
14.2
14.299999999999999
14.399999999999999
14.499999999999998
14.599999999999998
14.699999999999998
14.799999999999997
14.899999999999997
14.999999999999996
你可以使用math.big.Rat类型来准确表示有理数。
示例代码:
x := big.NewRat(14, 1)
y := big.NewRat(15, 1)
z := big.NewRat(1, 10)
for i := x; i.Cmp(y) < 0; i = i.Add(i, z) {
v, _ := i.Float64()
fmt.Println(v)
}
英文:
Not all real numbers can be represented precisely in binary floating point format, therefore looping over floating point number is asking for trouble.
From Wikipedia on Floating point
>The fact that floating-point numbers cannot precisely represent all real numbers, and that floating-point operations cannot precisely represent true arithmetic operations, leads to many surprising situations. This is related to the finite precision with which computers generally represent numbers.
>
>For example, the non-representability of 0.1 and 0.01 (in binary) means that the result of attempting to square 0.1 is neither 0.01 nor the representable number closest to it.
for i := 14.0; i < 15.0; i += 0.1 {
fmt.Println(i)
}
produces this
14
14.1
14.2
14.299999999999999
14.399999999999999
14.499999999999998
14.599999999999998
14.699999999999998
14.799999999999997
14.899999999999997
14.999999999999996
You may use math.big.Rat type to represent rational numbers accurately.
x := big.NewRat(14, 1)
y := big.NewRat(15, 1)
z := big.NewRat(1, 10)
for i := x; i.Cmp(y) < 0; i = i.Add(i, z) {
v, _ := i.Float64()
fmt.Println(v)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论