24

C++ で、浮動小数点値 (float) を固定小数点(int、16:16 または 24:8)に変換する一般的な方法は何ですか?

編集:明確にするために、固定小数点値には整数部分と小数部分の 2 つの部分があります。整数部分は、符号付きまたは符号なしの整数データ型で表すことができます。小数部分は、符号なし整数データ型で表されます。

わかりやすくするために、お金にたとえてみましょう。小数部分は、セント (ドルの小数部分) を表す場合があります。'cents' データ型の範囲は 0 ~ 99 です。固定小数点演算に 8 ビットの符号なし整数を使用する場合、小数部分は 256 の均等に割り切れる部分に分割されます。

これで問題が解決することを願っています。

4

6 に答える 6

31

どうぞ:

// A signed fixed-point 16:16 class
class FixedPoint_16_16
{
    short          intPart;
    unsigned short fracPart;

public:
    FixedPoint_16_16(double d)
    {
        *this = d; // calls operator=
    }

    FixedPoint_16_16& operator=(double d)
    {
        intPart = static_cast<short>(d);
        fracPart = static_cast<unsigned short>
                    (numeric_limits<unsigned short> + 1.0)*d);
        return *this;
    }

    // Other operators can be defined here
};

編集:これは、固定小数点数を処理する別の一般的な方法 (および KPexEA が指摘した) に基づく、より一般的なクラスです。

template <class BaseType, size_t FracDigits>
class fixed_point
{
    const static BaseType factor = 1 << FracDigits;

    BaseType data;

public:
    fixed_point(double d)
    {
        *this = d; // calls operator=
    }

    fixed_point& operator=(double d)
    {
        data = static_cast<BaseType>(d*factor);
        return *this;
    }

    BaseType raw_data() const
    {
        return data;
    }

    // Other operators can be defined here
};


fixed_point<int, 8> fp1;           // Will be signed 24:8 (if int is 32-bits)
fixed_point<unsigned int, 16> fp1; // Will be unsigned 16:16 (if int is 32-bits)
于 2008-10-09T15:27:11.447 に答える
25

浮動小数点から整数へのキャストは小数部分を破棄するため、その小数を固定小数点として保持したい場合は、浮動小数点を乗算してからキャストします。以下のコードはオーバーフローをチェックしません。

16:16が必要な場合

double f = 1.2345;
int n;

n=(int)(f*65536);

24:8が必要な場合

double f = 1.2345;
int n;

n=(int)(f*256);
于 2008-10-09T15:29:14.407 に答える
7

**** 編集** :私の最初のコメントはケビンの編集の前に適用されますが、後世のためにここに残しておきます。ここでは、答えがすぐに変わることがあります。

Kevin のアプローチの問題点は、固定小数点では通常、保証されたワード サイズ (通常は 32 ビット) にパックすることです。2 つの部分を別々に宣言すると、コンパイラの構造パッキングの気まぐれに任せられます。はい、強制できますが、16:16 表現以外では機能しません。

KPexEA は、すべてを int にパックすることでよりマークに近づきますが、32 ビットで明示的にするために「signed long」を使用します。次に、彼のアプローチを使用して固定小数点値を生成し、ビット スライスでコンポーネント パーツを再度抽出します。彼の提案は、24:8 のケースもカバーしています。

(そして、 static_cast だけを提案した他のすべての人.....あなたは何を考えていましたか? ;))

于 2008-10-09T16:11:50.330 に答える
1

最良の回答を書いた人に回答を与えましたが、ここを指す関連する質問コードを実際に使用しました。

テンプレートを使用し、ブースト ライブラリへの依存関係を簡単に捨てることができました。

于 2008-10-31T13:29:24.227 に答える
0

これは浮動小数点から整数への変換には問題ありませんが、OPは固定小数点も必要でした。

さて、C ++でそれをどのように行うかはわかりません(C ++は私がすぐに考えることができるものではありません)。おそらく、スケーリングされた整数のアプローチを試してください。つまり、32ビットまたは64ビットの整数を使用し、プログラムで最後の6桁を小数点の右側に割り当てます。

于 2008-10-09T15:28:02.523 に答える
-3

固定小数点数のC++には組み込みのサポートはありません。最善の策は、doubleを受け取り、それらを変換するラッパー'FixedInt'クラスを作成することです。

変換する一般的な方法については...int部分は十分に簡単です。値の整数部分を取得し、それを上位ビットに格納するだけです...小数部分は次の行に沿ったものになります。

for (int i = 1; i <= precision; i++)
{
   if (decimal_part > 1.f/(float)(i + 1)
   {
      decimal_part -= 1.f/(float)(i + 1);
      fixint_value |= (1 << precision - i);
   }
}

これにはまだバグが含まれている可能性がありますが

于 2008-10-09T15:32:18.007 に答える