我花了几分钟调试一个问题,该问题追踪到使用“Linear.normalize”时接近于零的“线性”截断值。具体来说,我对非常小的三角形进行叉积并对结果进行归一化,令人惊讶的是,结果表现错误,直到我注意到问题所在并将叉积乘以 10000。
为什么这是必要的?我怎样才能摆脱这种行为?
编辑:只是为了好玩,here is a video of the bug 。请注意,当近似球体的三角形数量足够大时,球体就会失去颜色?是的,祝调试顺利...!
最佳答案
查看source对于标准化
,您会看到它被定义为
-- | Normalize a 'Metric' functor to have unit 'norm'. This function
-- does not change the functor if its 'norm' is 0 or 1.
normalize :: (Floating a, Metric f, Epsilon a) => f a -> f a
normalize v = if nearZero l || nearZero (1-l) then v else fmap (/sqrt l) v
where l = quadrance v
这意味着,如果您的点的大小确实接近 0,您最终会得到错误的值。为了避免这种情况,您可以编写自己的 normalize
函数,而不进行此检查
normalize' :: (Floating a, Metric f) => f a -> f a
normalize' v = fmap (/ sqrt l) v where l = quadrance v
如果幸运的话,它应该可以解决您的问题。
解决这个问题的另一种方法可能是扩大你的值,执行计算,然后缩小它们,类似于
normalize' factor = (* factor) . normalize . (/ factor)
所以你可以打电话
normalize' 10e-10 (V3 1e-10 2e-10 3e-10)
相反,但由于 IEEE float 的存储方式,这很容易引入舍入误差。
编辑: 正如 cchalmers 指出的那样,这已经在 Linear.Metric
中作为 signorm
实现,因此请改用该函数。
关于haskell - "Linear"使用 `normalize` 时包截断值接近 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27910808/