3

我花了几分钟调试一个问题,该问题追踪到使用“Linear.normalize”时接近于零的“线性”截断值。具体来说,我正在取非常小的三角形的叉积并对结果进行归一化,令人惊讶的是,它的行为是错误的,直到我注意到出了什么问题并将叉积乘以 10000。

为什么这甚至是必要的?我怎样才能摆脱这种行为?

编辑:只是为了好玩,这是一个错误的视频。请注意,当近似它的三角形数量足够大时,球体会失去颜色?是的,祝你调试好运......!

4

1 回答 1

3

查看 的源代码normalize您会看到它被定义为

-- | 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 浮点数的存储方式,这很容易引入舍入误差。

编辑:正如 cchalmers 指出的那样,这已经实现为signormin Linear.Metric,因此请改用该函数。

于 2015-01-12T21:23:51.577 回答