将 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 的解决方案。由于循环的原因,它的效率较低,但它适用于浮点型和双精度型,不使用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;
}
In C++, I have a bigint class that can hold an integer of arbitrary size.
I'd like to convert large float or double numbers to bigint.
I have a working method, but it's a bit of a hack. I used IEEE 754 number specification to get the binary sign, mantissa and exponent of the input number.
Here is the code (Sign is ignored here, that's not important):
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;
It works, but it's rather ugly, and I don't know how portable it is. Is there a better way to do this? Is there a less ugly, portable way to extract the binary mantissa and exponent from a float or double?
Thanks for the answers. For posterity, here is a solution using frexp. It's less efficient because of the loop, but it works for float and double alike, doesn't use reinterpret_cast or depend on any knowledge of floating point number representations.
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您通常不能使用 frexp(), frexpf(), frexpl 提取值吗()?
Can't you normally extract the values using frexp(), frexpf(), frexpl()?
我喜欢你的解决方案!它让我走上了正轨。
不过,我建议一件事 - 为什么不一次获得一堆位并且几乎总是消除任何循环?我实现了一个像这样的 float-to-bigint 函数:(
顺便说一句,我不知道有一种简单的方法来放入浮点二次方常量,所以我定义了 float_pow_2 如下):
I like your solution! It got me on the right track.
I'd recommend one thing though - why not get a bunch of bits all at once and almost always eliminate any looping? I implemented a float-to-bigint function like this:
(By the way, I don't know of an easy way to put in floating point power-of-two constants, so I defined float_pow_2 as follows):
如果 float 始终包含整数值,只需将其转换为 int:float_to_int = (unsigned long) 输入。
顺便说一句,77e12 溢出了一个浮点。双精度型将保存它,但随后您将需要此强制转换:(unsigned long long) 输入。
If the float always contains an integral value, just cast it to int: float_to_int = (unsigned long) input.
BTW, 77e12 overflows a float. A double will hold it, but then you'll need this cast: (unsigned long long) input.