首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“几乎可除”

“几乎可除”
EN

Stack Overflow用户
提问于 2010-03-22 12:10:25
回答 7查看 627关注 0票数 12

我想检查一个浮点值是否“接近”32的倍数。例如,64.1几乎可以被32整除,63.9也是如此。

现在我正在做这件事:

代码语言:javascript
复制
#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
}

有更好的方法吗?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-03-22 12:18:34

那么,你可以通过再减去32一次来去掉第二个fmodf,从下面得到mod。

代码语言:javascript
复制
  if( offset < NEARLY_DIVISIBLE )
   {
       // it's near from above
   }
   else if( offset-32.0f>-1*NEARLY_DIVISIBLE)
   {
       // it's near from below
   }
票数 3
EN

Stack Overflow用户

发布于 2010-03-22 12:33:34

在符合标准的C实现中,应该使用remainder函数而不是fmod

代码语言:javascript
复制
#define NEARLY_DIVISIBLE 0.1f
float offset = remainderf(val, 32.0f);
if (fabsf(offset) < NEARLY_DIVISIBLE) {
    // Stuff
}

如果是在不兼容的平台上(例如MSVC++),那么不幸的是remainder不可用。我认为在这种情况下,快速乘法的答案是相当合理的。

票数 2
EN

Stack Overflow用户

发布于 2010-03-22 17:30:48

您提到,您必须使用32测试接近可分性。下面的理论应该适用于对2的幂的近似可除性测试:

代码语言:javascript
复制
#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);
}

我们所做的是强制浮点,并将浮点+阈值设置为长。

代码语言:javascript
复制
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整除的数字。

代码语言:javascript
复制
#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);
}

到目前为止似乎工作得很好!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2489992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档