Haskell &引用;“线性”;使用“normalize”时包截断接近0的值`

Haskell &引用;“线性”;使用“normalize”时包截断接近0的值`,haskell,haskell-linear,Haskell,Haskell Linear,我花了几分钟调试了一个问题,这个问题可以追溯到使用“Linear.normalize”时截断接近零的值的“Linear”。具体地说,我取了非常小的三角形的叉积并对结果进行标准化,结果令人惊讶地表现出错误,直到我注意到错误并将叉积乘以10000 为什么这是必要的?我怎样才能摆脱那种行为 编辑:只是为了好玩。请注意,当接近球体的三角形数量足够大时,球体会失去颜色?是的,祝你好运 查看fornormalize,您将看到它的定义为 -- | Normalize a 'Metric' functor to

我花了几分钟调试了一个问题,这个问题可以追溯到使用“Linear.normalize”时截断接近零的值的“Linear”。具体地说,我取了非常小的三角形的叉积并对结果进行标准化,结果令人惊讶地表现出错误,直到我注意到错误并将叉积乘以10000

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

编辑:只是为了好玩。请注意,当接近球体的三角形数量足够大时,球体会失去颜色?是的,祝你好运

查看for
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指出的,这已经在
Linear.Metric
中实现为
signorm
,因此请改用该函数。

您使用了哪些值?这可能是由于IEEE浮点格式而不是线性包的数学。请注意,规格化函数使用
linear.Epsilon.nearZero
函数,它肯定会截断您的值。您的
normalize'
只是
signorm
(也在
linear.Metric
中)@cchalmers我要指出的是,我以前没有使用
linear
软件包的经验,所以我只是开始阅读源代码并四处探索一下。有趣的是,我只是想确定一下,signorm的确切含义是什么?它是在做其他事情(可能是用信号?)还是仅仅是一个无截断的规范化?