为什么除法产生的结果与浮点数乘以分数的结果截然不同
我理解为什么浮点数不能进行比较,并且知道尾数和指数二进制表示,但我不是专家,今天我遇到了一些我不明白的事情:
也就是说,假设你有类似的东西:
float denominator, numerator, resultone, resulttwo;
resultone = numerator / denominator;
float buff = 1 / denominator;
resulttwo = numerator * buff;
给我的了解不同的失败会产生不同的结果,这并不罕见。但在某些边缘情况下,这两个结果似乎有很大不同。更具体地说,在我的 GLSL 代码中计算 Cook-Torrance 光照模型的 Beckmann 面斜率分布:
float a = 1 / (facetSlopeRMS * facetSlopeRMS * pow(clampedCosHalfNormal, 4));
float b = clampedCosHalfNormal * clampedCosHalfNormal - 1.0;
float c = facetSlopeRMS * facetSlopeRMS * clampedCosHalfNormal * clampedCosHalfNormal;
facetSlopeDistribution = a * exp(b/c);
非常不同的结果
float a = (facetSlopeRMS * facetSlopeRMS * pow(clampedCosHalfNormal, 4));
facetDlopeDistribution = exp(b/c) / a;
产生与为什么会产生 ?第二种表达形式是有问题的。
如果我说尝试将表达式的第二种形式添加到颜色中,我会得到黑色,即使表达式应始终计算为正数。我得到的是无穷大吗?一个NaN?如果是这样为什么?
I understand why floating point numbers can't be compared, and know about the mantissa and exponent binary representation, but I'm no expert and today I came across something I don't get:
Namely lets say you have something like:
float denominator, numerator, resultone, resulttwo;
resultone = numerator / denominator;
float buff = 1 / denominator;
resulttwo = numerator * buff;
To my knowledge different flops can yield different results and this is not unusual. But in some edge cases these two results seem to be vastly different. To be more specific in my GLSL code calculating the Beckmann facet slope distribution for the Cook-Torrance lighitng model:
float a = 1 / (facetSlopeRMS * facetSlopeRMS * pow(clampedCosHalfNormal, 4));
float b = clampedCosHalfNormal * clampedCosHalfNormal - 1.0;
float c = facetSlopeRMS * facetSlopeRMS * clampedCosHalfNormal * clampedCosHalfNormal;
facetSlopeDistribution = a * exp(b/c);
yields very very different results to
float a = (facetSlopeRMS * facetSlopeRMS * pow(clampedCosHalfNormal, 4));
facetDlopeDistribution = exp(b/c) / a;
Why does it? The second form of the expression is problematic.
If I say try to add the second form of the expression to a color I get blacks, even though the expression should always evaluate to a positive number. Am I getting an infinity? A NaN? if so why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我没有详细介绍你的数学,但你必须意识到,所有这些幂和指数很容易产生小错误。您应该尝试用
var + e(var)
替换所有变量var
(在纸面上,是的)并导出总误差的表达式 - 无需在步骤之间进行简化,因为这就是错误的来源!这也是计算流体动力学中的一个非常常见的问题,如果您的网格与模拟流没有正确对齐,您可以观察到诸如“数值扩散”之类的问题。
因此,要清楚地了解最大误差的来源,并尽可能重写方程以最小化数字误差。
编辑:为了澄清,举一个例子
假设您有一些变量
x
和一个表达式y=exp(x)
。x
中的误差表示为e(x)
,并且与x
相比较小(例如e(x)/x
e(x)/x
e(x)/x
,但请注意,这取决于您使用的类型)。那么你可以说,x
)。 0.0001所以
exp(x)
的绝对误差被放大了,这意味着在x=0
周围确实没有问题(这并不奇怪,因为在该点exp(x)
的斜率等于x
) 的斜率,但对于大的x
你会注意到这一点。相对误差将是,
而
x
中的相对误差为,因此您将
x
因子添加到相对误差中。I didn't go through your mathematics in detail, but you must be aware that small errors get pumped up easily by all these powers and exponentials. You should try and substitute all variables
var
withvar + e(var)
(on paper, yes) and derive an expression for the total error - without simplifying in between steps, because that's where the error comes from!This is also a very common problem in computational fluid dynamics, where you can observe things like 'numeric diffusion' if your grid isn't properly aligned with the simulated flow.
So get a clear grip on where the biggest errors come from, and rewrite equations where possible to minimize the numeric error.
edit: to clarify, an example
Say you have some variable
x
and an expressiony=exp(x)
. The error inx
is denotede(x)
and is small compared tox
(saye(x)/x < 0.0001
, but note that this depends on the type you are using). Then you could say thatSo there's a magnification of the absolute error of
exp(x)
, meaning that aroundx=0
there's really no issue (not a surprise, since at that point the slope ofexp(x)
equals that ofx
) , but for bigx
you will notice this.The relative error would then be
whilst the relative error in
x
wasso you added a factor of
x
to the relative error.