将float转换为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;
它有效,但它很丑,我不知道它的便携性。 有一个更好的方法吗? 是否有一种不太丑陋,便携的方式来从浮点数或双精度中提取二进制尾数和指数?
感谢您的答案。 为了后代,这是一个使用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;
}
你不能通常使用frexp(),frexpf(),frexpl()来提取值吗?
我喜欢你的解决方案! 这让我走上了正轨。
尽管我会推荐一件事 - 为什么不一次性得到一堆,几乎总是消除任何循环? 我实现了像这样的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);
};
如果float始终包含一个整数值,只需将其转换为int:float_to_int =(unsigned long)输入。
BTW,77e12溢出浮动。 一个double会保存它,但是你需要这个cast:(unsigned long long)输入。
链接地址: http://www.djcxy.com/p/85581.html上一篇: Convert float to bigint (aka portable way to get binary exponent & mantissa)