12

浮動小数点値が 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
}

これを行うためのより良い方法がありますか?

4

7 に答える 7

3

まあ、32 をもう一度引くだけで 2 番目の 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-22T04:18:33.800 に答える
2

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);
}

私たちが行っているのは、floatを強制し、float+THRESHOLDをlongに強制することです。

f       (long) f    (long) (f + THRESHOLD)
63.9    63          64
64      64          64
64.1    64          64

ここで、(長い)fが32で割り切れるかどうかをテストします。下位5ビットを確認してください。すべてゼロに設定されている場合、数値は32で割り切れます。これにより、一連の誤検知が発生します。変換すると、64.2から64.8になります。長い間、64であり、最初のテストに合格します。したがって、切り捨てられた形式とfの差がTHRESHOLD以下であるかどうかを確認します。

これにも問題があります。f-(float)l2 <= THRESHOLDは64と64.1には当てはまりますが、63.9には当てはまりません。したがって、64未満の数値の例外を追加します(これは、THRESHOLDによってインクリメントされ、その後longに強制変換されると、最初のテストに含まれる必要があることに注意してください)、次のように指定します。下位5ビットはゼロではありません。これは63(1000000-1 == 1 11111)にも当てはまります。

これらの3つのテストの組み合わせは、数値が32で割り切れるかどうかを示します。私はこれが明確であることを願っています、私の奇妙な英語を許してください。

他の3の累乗への拡張性をテストしました。次のプログラムは、128で割り切れる383.5から388.4までの数値を出力します。

#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);
}

これまでのところうまく機能しているようです!

于 2010-03-22T09:30:47.587 に答える
2

標準準拠の C 実装では、次のremainder代わりに関数を使用しfmodます。

#define NEARLY_DIVISIBLE 0.1f
float offset = remainderf(val, 32.0f);
if (fabsf(offset) < NEARLY_DIVISIBLE) {
    // Stuff
}

非準拠のプラットフォーム (MSVC++ など) 上にある場合remainderは、残念ながら利用できません。その場合、高速乗算の答えはかなり合理的だと思います。

于 2010-03-22T04:33:34.327 に答える
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
}

それでも上と下からチェックしたい場合は、abs を削除して、差が >0 か <0 かを確認できます。

于 2010-03-22T14:53:57.753 に答える
0

これには、fmodf を 2 回使用する必要はありません。

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;
}
于 2010-03-22T21:11:43.917 に答える
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);
}
于 2010-03-22T05:07:44.490 に答える
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;
}
于 2010-03-22T05:23:46.383 に答える