haskell - "Linear"使用 `normalize` 时包截断值接近 0

标签 haskell haskell-linear

我花了几分钟调试一个问题,该问题追踪到使用“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/

相关文章:

haskell - 如何在 Haskell 上通用地派生 Additive,而不定义 Applicative 实例?

haskell - protected 管道的行为与使用等待的管道相同吗?

list - 你如何在 Haskell 中编写函数 'pairs'?

parsing - 生成解析器,在另一个解析器的输出上运行接收到的解析器并单子(monad)连接结果

parsing - 如何使用 alex/haskell 进行 python 样式的缩进/缩进标记?

haskell - 在保留评论的同时将 Coq 提取到 Haskell

haskell - 如何使用 Haskell 库 Linear 缩放向量?