数学ライブラリのないプラットフォーム用に開発しているので、独自のツールを構築する必要があります。現在の分数を取得する方法は、フロートを固定小数点に変換し((float)0xFFFFを乗算し、intにキャスト)、下部のみを取得し(0xFFFFを使用してマスク)、再びフロートに変換します。
しかし、その不正確さが私を殺しています。 Frac()およびInvFrac()関数を使用して、アンチエイリアス処理された線を描画しています。 modf
を使用すると、完全に滑らかな線になります。私自身の方法では、精度の低下によりピクセルが動き回ります。
これは私のコードです:
const float fp_amount = (float)(0xFFFF);
const float fp_amount_inv = 1.f / fp_amount;
inline float Frac(float a_X)
{
return ((int)(a_X * fp_amount) & 0xFFFF) * fp_amount_inv;
}
inline float Frac(float a_X)
{
return (0xFFFF - (int)(a_X * fp_amount) & 0xFFFF) * fp_amount_inv;
}
前もって感謝します!
私があなたの質問を正しく理解していれば、小数点以下の部分だけが欲しいですか?実際には分数(整数分子と分母)は必要ありませんか?
つまり、3.14159
と言って、0.14159
だけにしてください。番号がfloat f;
に格納されていると仮定すると、次のようになります。
f = f-(long)f;
これは、番号を挿入すると、次のように機能します。
0.14159 = 3.14159 - 3;
これにより、浮動小数点数の整数部分が削除され、小数部分のみが残ります。 floatをlongに変換すると、小数点以下が切り捨てられます。次に、元のフロートからそれを引くと、小数点以下のonlyが残ります。 float
タイプ(ほとんどのシステムでは8バイト)のサイズのため、ここではlongを使用する必要があります。整数(多くのシステムでは4バイトのみ)は、float
と同じ範囲の数値をカバーするのに十分な大きさである必要はありませんが、long
はそうである必要があります。
私が思ったように、modf
は算術自体を使用していません-すべてのシフトとマスクです、見てください ここ 。プラットフォームで同じアイデアを使用できませんか?
今日使用しているシステムでmodfがどのように実装されているかを確認することをお勧めします。 uClibcのバージョンを確認してください。
http://git.uclibc.org/uClibc/tree/libm/s_modf.c
(法的な理由により、BSDライセンスであるように見えますが、明らかに再確認する必要があります)
一部のマクロは定義されています here 。
定数にバグがあります。基本的に、数値を16ビット左シフトし、下位ビット以外のすべてをマスクしてから、再び16ビット右シフトしようとしています。シフトは2の累乗を乗算することと同じですが、2の累乗を使用していません。0から1だけ離れた0xFFFFを使用しています。これを0x10000に置き換えると、式が意図したとおりに機能します。
完全にはわかりませんが、仮数だけを考慮して指数を完全に忘れているだけなので、あなたがしていることは間違っていると思います。
実際の整数部分を見つけるには、指数を使用して仮数の値をシフトする必要があります。
32ビット浮動小数点の格納メカニズムの説明については、 ここ を参照してください。
多分あなたはこれが欲しいようです。
float f = something;
float fractionalPart = f - floor(f);
なぜ線画のために浮動小数点に行くのですか?固定小数点バージョンに固執し、代わりに整数/固定小数点ベースの線描画ルーチンを使用できます-Bresenhamが思い浮かびます。このバージョンにはエイリアスがありませんが、他にもエイリアスがあることは知っています。
あなたの方法は、小数部に16ビットがあることを前提としています(Mark Ransomが注記しているように、16ビットでシフトする必要があります(つまり、0x1000で乗算します)。それは本当ではないかもしれません。指数は、小数部分にあるビット数を決定するものです。
これを数式に入れるには、メソッドは(x modf 1.0)
なので ((x << 16) mod 1<<16) >> 16
、そして指数に依存するはずのハードコードされた16です-正確な置換はフロート形式に依存します。
1つのオプションは、fmod(x, 1)
を使用することです。
double frac(double val)
{
return val - trunc(val);
}
// frac(1.0) = 1.0 - 1.0 = 0.0 correct
// frac(-1.0) = -1.0 - -1.0 = 0.0 correct
// frac(1.4) = 1.4 - 1.0 = 0.4 correct
// frac(-1.4) = -1.4 - -1.0 = -0.4 correct
シンプルで、-veおよび+ veで機能します