C 这个数学舍入函数是如何工作的?
有人能解释一下这个函数的作用吗C 这个数学舍入函数是如何工作的?,c,math,rounding,C,Math,Rounding,有人能解释一下这个函数的作用吗 static inline void round_to_zero(volatile float *f) { *f += 1e-18; *f -= 1e-18; } 我的意思是,除了加1e-18再减去它,我明白这一点。但我不明白它会对传递给它的浮点产生什么影响。我试图理解它的原因是我在一些使用这个函数的代码中使用了double(我从float转换而来)。其音频代码,上述功能来自此库: 我想知道它是否能在双精度上正常工作,或者需要修改以获得双精度的额外精度
static inline void round_to_zero(volatile float *f)
{
*f += 1e-18;
*f -= 1e-18;
}
我的意思是,除了加1e-18再减去它,我明白这一点。但我不明白它会对传递给它的浮点产生什么影响。我试图理解它的原因是我在一些使用这个函数的代码中使用了double(我从float转换而来)。其音频代码,上述功能来自此库:
我想知道它是否能在双精度上正常工作,或者需要修改以获得双精度的额外精度。我怀疑这会敲掉最后几位数据,如果它们在浮点数中,就会将它们从浮点数中删除,尽管我不太明白是如何做到的。但我想如果它是这样的话,我需要改变指数来适应双精度
TIA,Pete下面的代码演示了该函数的功能
int main( void )
{
float a;
a = -1.0;
a /= 1e100;
printf( "%f\n", a );
round_to_zero( &a );
printf( "%f\n", a );
}
您需要知道的是,IEEE-754浮点数对于0
有两个可能的值。有一个正0
和一个负0
。round_to_zero
函数将负0转换为正0
双精度数字
1.0
的值1e-18
约为1lsb
。因此,我认为不需要任何修改就可以将该函数与double
一起使用(当然,除了更改参数类型之外)。认为我应该回到这里来添加以下细节
虽然将负零转换为正的答案是正确的,并且对我很有用,但还有更多的内容
将1e-18相加,然后从浮点中减去,确实可以消除浮点中非常低的数字。这在音频应用中使用,因为过滤器可以通过不断分割浮点数的函数循环小浮点数,从而产生更小的浮点数。一旦该数字变得非规范化(正如Caskey所提到的),许多CPU(包括x86)中该数字的处理速度将降低100倍
通过为该数据类型添加一个比非规范大小大得多的数字,可以消除该类型中存储的微小值。减去相同的较大值会导致类型保留零,如果处理,则不会影响处理速度。清除微小值的原因是类型中的有效位精度不足以容纳非常微小的值和刚刚添加的较大值
例如:
从值为1.0f的音频采样开始
将其通过一个40次除以10的函数,得到1e-40的值
v=0.0100000 e-38(浮点类型的精度约为8位小数,指数高达38,因此在内存中看起来就像我在这里写的那样)
这现在是浮点类型的非规范值,将导致cpu处理它的速度非常慢。如何摆脱减速?归零。因此:
增加1e-18;结果:
1.00000000 e-18(注意原始1e-40太小,如果其已持有更大的1e-18值,则无法用8位有效位表示)
然后减去1e-18值:
0.00000000 e-0
因此,我们产生了零,消除了原始的非规范值,我们的cpu感谢我们。看起来这是一个高度优化的代码,它依赖于IEEE754对非规范数的处理以及代码正在处理的预期数据类型()。除此之外,我无法理解它。@caskey
float
非规范数比这个小。谢谢-你能解释一下它是怎么做到的吗?为什么加上1e-18并减去它会有这种效果,我想知道它对可能通过的整个数字范围有什么影响。如果双精度的值1e-18是1lsb,那么它必须比浮点的值小得多,代码就是为这个值设计的,所以我想知道这个函数对浮点的影响是否与双精度的不同?因为我真的不理解它(尽管我理解删除符号的必要性),所以我怀疑细微的差异可能会使使用双精度的代码表现不同(未被发现)。@Pete--这个想法是,如果你从负0开始,然后加上1e-18会给你一个小的正数,减去1e-18等于0。如果从任何其他数字开始,加上和减去1e-18对该数字没有净影响。不管怎么说,这似乎是理论。