我想检查一个浮点值是否“接近”32的倍数。例如,64.1几乎可以被32整除,63.9也是如此。
现在我正在做这件事:
#define NEARLY_DIVISIBLE 0.1f
float offset = fmodf( val, 32.0f ) ;
if( offset < NEARLY_DIVISIBLE )
{
// its near from above
}
// if it was 63.9, then the remainder would be large, so add some then and check again
else if( fmodf( val + 2*NEARLY_DIVISIBLE, 32.0f ) < NEARLY_DIVISIBLE )
{
// its near from below
}有更好的方法吗?
发布于 2010-03-22 12:18:34
那么,你可以通过再减去32一次来去掉第二个fmodf,从下面得到mod。
if( offset < NEARLY_DIVISIBLE )
{
// it's near from above
}
else if( offset-32.0f>-1*NEARLY_DIVISIBLE)
{
// it's near from below
}发布于 2010-03-22 12:33:34
在符合标准的C实现中,应该使用remainder函数而不是fmod
#define NEARLY_DIVISIBLE 0.1f
float offset = remainderf(val, 32.0f);
if (fabsf(offset) < NEARLY_DIVISIBLE) {
// Stuff
}如果是在不兼容的平台上(例如MSVC++),那么不幸的是remainder不可用。我认为在这种情况下,快速乘法的答案是相当合理的。
发布于 2010-03-22 17:30:48
您提到,您必须使用32测试接近可分性。下面的理论应该适用于对2的幂的近似可除性测试:
#define THRESHOLD 0.11
int nearly_divisible(float f) {
// printf(" %f\n", (a - (float)((long) a)));
register long l1, l2;
l1 = (long) (f + THRESHOLD);
l2 = (long) f;
return !(l1 & 31) && (l2 & 31 ? 1 : f - (float) l2 <= THRESHOLD);
}我们所做的是强制浮点,并将浮点+阈值设置为长。
f (long) f (long) (f + THRESHOLD)
63.9 63 64
64 64 64
64.1 64 64现在我们测试(long) f是否能被32整除。只需检查较低的五位,如果它们都设置为0,则该数字可被32整除。这导致了一系列的假阳性: 64.2到64.8,当转换为long时,也是64,并将通过第一个测试。因此,我们检查它们的截断形式和f之间的差异是否小于或等于阈值。
这也有一个问题:F-(浮点) l2 <=阈值对于64和64.1是真的,但对63.9不是真的。因此,我们通过指定低5位不是零,为小于64的数字添加了一个例外(当以阈值递增并随后被强制为长整型时--请注意,讨论中的测试必须包含在第一个测试中--可以被32整除)。这将适用于63 (1000000 -1 == 1 11111)。
这三个测试的组合将表明该数字是否能被32整除。我希望这是清楚的,请原谅我奇怪的英语。
我刚刚测试了3的其他幂的可扩展性--下面的程序打印383.5到388.4之间的可以被128整除的数字。
#include <stdio.h>
#define THRESHOLD 0.11
int main(void) {
int nearly_divisible(float);
int i;
float f = 383.5;
for (i=0; i<50; i++) {
printf("%6.1f %s\n", f, (nearly_divisible(f) ? "true" : "false"));
f += 0.1;
}
return 0;
}
int nearly_divisible(float f) {
// printf(" %f\n", (a - (float)((long) a)));
register long l1, l2;
l1 = (long) (f + THRESHOLD);
l2 = (long) f;
return !(l1 & 127) && (l2 & 127 ? 1 : f - (float) l2 <= THRESHOLD);
}到目前为止似乎工作得很好!
https://stackoverflow.com/questions/2489992
复制相似问题