我想检查浮点值是否“几乎”是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
}
有更好的方法吗?
答案 0 :(得分:3)
if( offset < NEARLY_DIVISIBLE )
{
// it's near from above
}
else if( offset-32.0f>-1*NEARLY_DIVISIBLE)
{
// it's near from below
}
答案 1 :(得分:2)
在符合标准的C实现中,可以使用remainder
函数而不是fmod
:
#define NEARLY_DIVISIBLE 0.1f
float offset = remainderf(val, 32.0f);
if (fabsf(offset) < NEARLY_DIVISIBLE) {
// Stuff
}
如果一个人在不合规的平台上(例如MSVC ++),那么遗憾的是remainder
不可用。我认为fastmultiplication的答案在这种情况下是非常合理的。
答案 2 :(得分:2)
您提到必须使用 32 测试近似可分性。以下理论应该适用于针对两个权力的近似可分性测试:
#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);
}
我们正在做的是强制浮动,并将+ THRESHOLD浮动为长。
f (long) f (long) (f + THRESHOLD)
63.9 63 64
64 64 64
64.1 64 64
现在我们测试if(long)f是否可被32整除。只需检查低5位,如果它们都设置为零,则数字可以被32整除。这会导致一系列误报:64.2到64.8 ,当转换为long时,也是64,并且会通过第一次测试。因此,我们检查它们的截断形式和f之间的差异是否小于或等于THRESHOLD。
这也有问题:f - (float)l2&lt; = THRESHOLD对于64和64.1将保持为真,但对于63.9则不成立。因此,我们为小于64的数字添加一个例外(当由THRESHOLD递增并随后强制转换为长 - 注意所讨论的测试必须包含第一个测试 - 可被32整除),通过指定低5位不为零。这将适用于63(1000000 - 1 == 1 11111 )。
这三个测试的组合将指示该数字是否可被32整除。我希望这很清楚,请原谅我奇怪的英语。
我刚刚测试了其他三个幂的可扩展性 - 下面的程序打印出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);
}
到目前为止似乎运作良好!
答案 3 :(得分:0)
对于我收集的内容,您想要检测一个数字是否几乎可以被其他数字整除,对吧?
我会做这样的事情:
#define NEARLY_DIVISIBLE 0.1f
bool IsNearlyDivisible(float n1, float n2)
{
float remainder = (fmodf(n1, n2) / n2);
remainder = remainder < 0f ? -remainder : remainder;
remainder = remainder > 0.5f ? 1 - remainder : remainder;
return (remainder <= NEARLY_DIVISIBLE);
}
答案 4 :(得分:0)
我认为这是对的:
bool nearlyDivisible(float num,float div){
float f = num % div;
if(f>div/2.0f){
f=f-div;
}
f=f>0?f:0.0f-f;
return f<0.1f;
}
答案 5 :(得分:0)
为什么你不只是除以32,然后舍入并取圆整数和实际结果之间的差异?
像(原谅未经测试的/伪代码,没有时间查找):
#define NEARLY_DIVISIBLE 0.1f
float result = val / 32.0f;
float nearest_int = nearbyintf(result);
float difference = abs(result - nearest_int);
if( difference < NEARLY_DIVISIBLE )
{
// It's nearly divisible
}
如果您仍想从上方和下方进行检查,您可以删除腹肌,并检查差异是否> 0或<0。
答案 6 :(得分:0)
这不使用modf两次。
int main(void)
{
#define NEARLY_DIVISIBLE 0.1f
#define DIVISOR 32.0f
#define ARRAY_SIZE 4
double test_var1[ARRAY_SIZE] = {63.9,64.1,65,63.8};
int i = 54;
double rest;
for(i=0;i<ARRAY_SIZE;i++)
{
rest = fmod(test_var1[i] ,DIVISOR);
if(rest < NEARLY_DIVISIBLE)
{
printf("Number %f max %f larger than a factor of the divisor:%f\n",test_var1[i],NEARLY_DIVISIBLE,DIVISOR);
}
else if( -(rest-DIVISOR) < NEARLY_DIVISIBLE)
{
printf("Number %f max %f less than a factor of the divisor:%f\n",test_var1[i],NEARLY_DIVISIBLE,DIVISOR);
}
}
return 0;
}