4

C++ には、任意のサイズの整数を保持できる bigint クラスがあります。

大きな float または double の数値を bigint に変換したいと思います。私は作業方法を持っていますが、それは少しハックです。IEEE 754 数値仕様を使用して、入力数値の 2 進符号、仮数、および指数を取得しました。

コードは次のとおりです (Sign はここでは無視されますが、重要ではありません)。

 float input = 77e12;
 bigint result;

 // extract sign, exponent and mantissa, 
 // according to IEEE 754 single precision number format
 unsigned int *raw = reinterpret_cast<unsigned int *>(&input); 
 unsigned int sign = *raw >> 31;
 unsigned int exponent = (*raw >> 23) & 0xFF;
 unsigned int mantissa = *raw & 0x7FFFFF;

 // the 24th bit is always 1.
 result = mantissa + 0x800000;

 // use the binary exponent to shift the result left or right
 int shift = (23 - exponent + 127);
 if (shift > 0) result >>= shift; else result <<= -shift;

 cout << input << " " << result << endl;

動作しますが、かなり醜く、移植性がどの程度かわかりません。これを行うより良い方法はありますか?float または double からバイナリの仮数部と指数部を抽出する、より醜く移植性の低い方法はありますか?


答えてくれてありがとう。後世のために、frexp を使用したソリューションを次に示します。ループのために効率が低下しますが、float と double の両方で機能し、reinterpret_cast を使用せず、浮動小数点数表現の知識に依存しません。

float input = 77e12;
bigint result;

int exponent;
double fraction = frexp (input, &exponent);
result = 0;
exponent--;
for (; exponent > 0; --exponent)
{
    fraction *= 2;
    if (fraction >= 1)
    {
        result += 1;
        fraction -= 1;
    }
    result <<= 1;
}   
4

3 に答える 3

8

frexp() 、 frexpf() 、 frexpl()を使用して値を正常に抽出できませんか?

于 2010-01-25T16:52:49.720 に答える
1

私はあなたのソリューションが好きです!それは私を正しい軌道に乗せました。

ただし、1 つのことをお勧めします。一度に大量のビットを取得して、ほとんどの場合ループをなくしてみませんか? 次のような float-to-bigint 関数を実装しました。

template<typename F>
explicit inline bigint(F f, typename std::enable_if<(std::is_floating_point<F>::value)>::type* enable = nullptr) {
    int exp;
    F fraction = frexp(fabs(f),&exp);
    F chunk = floor(fraction *= float_pow_2<F,ulong_bit_count>::value);
    *this = ulong(chunk); // will never overflow; frexp() is guaranteed < 1
    exp -= ulong_bit_count;
    while (sizeof(F) > sizeof(ulong) && (fraction -= chunk)) // this is very unlikely
    {
        chunk = floor(fraction *= float_pow_2<F,ulong_bit_count>::value);
        *this <<= ulong_bit_count;
        (*this).data[0] = ulong(chunk);
        exp -= ulong_bit_count;
    }
    *this <<= exp;
    sign = f < 0;
}

(ちなみに、浮動小数点の 2 のべき乗定数を簡単に入れる方法がわからないので、float_pow_2 を次のように定義しました):

template<typename F, unsigned Exp, bool Overflow = (Exp >= sizeof(unsigned))>
struct float_pow_2 {
    static constexpr F value = 1u << Exp;
};
template<typename F, unsigned Exp>
struct float_pow_2<F,Exp,true> {
    static constexpr F half = float_pow_2<F,Exp/2>::value;
    static constexpr F value = half * half * (Exp & 1 ? 2 : 1);
};
于 2011-03-21T04:56:04.050 に答える
-1

float が常に整数値を含む場合は、int にキャストするだけです: float_to_int = (unsigned long) 入力。

ところで、77e12 は float をオーバーフローします。double はそれを保持しますが、このキャストが必要になります: (unsigned long long) 入力。

于 2010-01-25T19:31:27.780 に答える