求助:小数的数据精度问题(以及关于print的小问题)

描述

我需要计算一些满足 10^{-6} 级别精度的结果,但是在计算过程中,发现由于中间变量的精度损失,无法获得满足精度的最终解答。

问题

如代码所示,是一个简单的将紧凑形式应力向量变为一个矩阵的简单操作函数,输入的数据 -0.742128、-1.731632 经过在func内赋值,变成了 -0.742128014565、-1.731631994247,但 -0.000001、0.0 却保持不变。这还是在使用 ti.f64 数据类型下的结果,如果使用默认的 ti.f32 会产生更大的误差(变成 -0.7421280256、-1.7316319232),而直接使用Python就没有这个问题。

计算过程从初始化赋值就开始出现误差,在后续各种运算过程后,最终结果的误差将难以接受(如最终结果应为 0.0,但在 ti.f32 下,只能算到 0.000000029802)。而且我设置了迭代计算来提高精度,但猜测也是由于这个数值精度的问题导致迭代到最后始终是一样的结果,无法再小下去。

因此我了解了一下float的精度范围,似乎按照float32、float64的精度范围,不应该出现这样的问题?

请问这种数值误差应如何避免?

代码

import taichi as ti
ti.init(debug=True)

@ti.func
def get_f_stress3(f_stress):
    res = ti.Matrix([[f_stress[0], f_stress[2], 0.0], [f_stress[2], f_stress[1], 0.0], [0.0, 0.0, f_stress[3]]], ti.f64)
    return res

@ti.kernel
def foo():
    stress = get_f_stress3(f_stress)
    print("σ =", stress)

if __name__ == "__main__":
    f_stress = ti.Vector([-0.742128, -1.731632, -0.000001, -0.742128], ti.f64)
    foo()

Output:

[Taichi] version 1.0.0, llvm 10.0.0, commit 6a15da85, win, python 3.8.1
[Taichi] Starting on arch=x64
蟽 = [[-0.742128014565, -0.000001000000, 0.000000000000], [-0.000001000000, -1.731631994247, 0.000000000000], [0.000000000000, 0.000000000000, -0.742128014565]]

另一个小问题

偶然发现如果想在 ti.kernelprint 一个希腊字母,就会出现奇怪的汉字(σ → 蟽,λ → 位)。在Python中 print 则是正常的。都是通过 Windows + . 选择输入的希腊字母。这是为什么呢?

1 个赞

float32 类型只有 6-7 位精度,所以出现 0.000000029802 的误差其实挺正常的。由于 Taichi 默认使用 float32, 你输入的常数也会转成 float32。解决方法也很简单, ti.init 里面加入 default_fp=ti.f64 就行了。

import taichi as ti
ti.init(debug=True, default_fp=ti.f64)

@ti.func
def get_f_stress3(f_stress):
    res = ti.Matrix([[f_stress[0], f_stress[2], 0.0], [f_stress[2], f_stress[1], 0.0], [0.0, 0.0, f_stress[3]]], ti.f64)
    return res

@ti.kernel
def foo():
    stress = get_f_stress3(f_stress)
    print("σ =", stress)

if __name__ == "__main__":
    f_stress = ti.Vector([-0.742128, -1.731632, -0.000001, -0.742128], ti.f64)
    foo()

输出:

σ = [[-0.742128000000, -0.000001000000, 0.000000000000], [-0.000001000000, -1.731632000000, 0.000000000000], [0.000000000000, 0.000000000000, -0.742128000000]]
1 个赞

非常感谢!没有想到居然如此简单,顿觉基础知识还是不够哇!

之前我尝试在程序中几乎每个地方都加了个 ti.f64,但是算出来还是不对。现在尝试在主程序文件开始的地方加了default_fp=ti.f64 后,只需要把ggui绘图相关的少数几个变量设置成 ti.f32 就行了!:star_struck:最终结果也变得完全精确了起来!

2 个赞