有可能将浮点数双倍往返到两个十进制整数并保真吗?

ipm*_*mcc 0 c ieee-754

我试图辨别是否有可能将双精度IEEE浮点值分解为两个整数,并在以后以完全保真度重新组合它们.想象一下这样的事情:

double foo = <inputValue>;
double ipart = 0;
double fpart = modf(foo, &ipart);

int64_t intIPart = ipart;
int64_t intFPart = fpart * <someConstant>;

double bar = ((double)ipart) + ((double)intFPart) / <someConstant>;

assert(foo == bar);
Run Code Online (Sandbox Code Playgroud)

从逻辑上讲,任何64位数量都可以存储在128位中(即只存储文字位.)这里的目标是将整数部分和double的小数部分分解为整数表示(与API接口)其存储格式我无法控制)并在重新组合两个64位整数时返回一个精确的双精度数.

我对IEEE浮点有一个概念性的理解,我得到的是双精度存储base-2.我凭经验证明,采用上述方法,有时foo != bar甚至是非常大的值<someConstant>.我已经离开学校一段时间了,我不能完全理解这个循环,理解这是否可能给出不同的基础(或其他因素).

编辑:

我想这是在我的大脑中隐含/理解但未在此捕获:在这种情况下,我保证问题中双重的总体幅度将始终在+/- 2 ^ 63(和> 2 ^ -64)之内.根据这种理解,整数部分保证适合64位int类型,然后我的期望是小数精度为~16位,小数部分也应该很容易在64位int类型中表示.

Eri*_*hil 5

如果您知道数字在[-2 63,+ 2 63 ]中且ULP(数字中最低位的值)至少为2-63,那么您可以使用:

double ipart;
double fpart = modf(foo, &ipart);

int64_t intIPart = ipart;
int64_t intFPart = fpart * 0x1p63;

double bar = intIPart + intFPart * 0x1p-63;
Run Code Online (Sandbox Code Playgroud)

如果你只想要几个可以重构值并且不关心那些整数含义的整数(例如,它们中没有一个是整数部分),那么你可以frexp用来反汇编号进入其有效数字(带符号)和指数,你可以ldexp用来重组它:

int exp;
int64_t I = frexp(foo, &exp) * 0x1p53;
int64_t E = exp;

double bar = ldexp(I, E-53);
Run Code Online (Sandbox Code Playgroud)

此代码适用于IEEE-754 64位二进制浮点对象的任何有限值.它不支持无穷大或NaN.

它甚至可以打包IE成一个单一的int64_t,如果你想要去的麻烦.