将float转换为bigint(也称为可移植方式以获取二进制指数和尾数)

时间:2010-01-25 16:48:36

标签: c++ floating-point ieee-754 bigint

在C ++中,我有一个bigint类,可以保存任意大小的整数。

我想将大型浮点数或双数字转换为bigint。 我有一个工作方法,但它有点像黑客。我使用IEEE 754数字规范来获得输入数字的二进制符号,尾数和指数。

这是代码(这里忽略了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;
}   

3 个答案:

答案 0 :(得分:8)

您通常无法使用frexp(), frexpf(), frexpl()提取值吗?

答案 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;
}

(顺便说一句,我不知道一个简单的方法来放入浮点幂的两个常数,所以我将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);
};

答案 2 :(得分:-1)

如果float总是包含一个整数值,只需将其强制转换为int:float_to_int =(unsigned long)输入。

BT,77e12溢出浮动。一个double会保持它,但是你需要这个演员:( unsigned long long)输入。