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);
}
これまでのところうまく機能しているようです!