c - 是否可以保真地将浮点 double 往返到两位十进制整数?

标签 c ieee-754

我正在尝试辨别是否可以将 double 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);

逻辑上很明显,任何 64 位数量都可以存储在 128 位中(即只存储文字位。)这里的目标是将 double 的整数部分和小数部分分解为整数表示形式(以接口(interface)和存储格式不受我控制的 API)并在重组这两个 64 位整数时返回一个精确的 double 值。

我对 IEEE float 有一个概念性的理解,我知道 double 值是以 2 为底存储的。根据经验,我观察到使用上述方法,有时 foo != bar对于非常大的 <someConstant> 值.我已经离开学校一段时间了,我无法完全理解在不同的基础(或其他一些因素)下这是否可能的理解。

编辑:

我想这在我的大脑中是暗示/理解的,但没有在这里捕捉到:在这种情况下,我保证问题中 double 的总体大小将始终在 +/- 2^63(和 > 2^ -64).有了这种理解,整数部分就可以保证适合 64 位 int 类型,那么我的期望是,有了 ~16 位的十进制精度,小数部分也应该可以很容易地用 64 位 int 类型表示。

最佳答案

如果你知道数字在 [–263, +263) 并且 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;

如果您只想要几个可以从中重构值的整数并且不关心这些整数的含义(例如,其中一个不必是整数部分),那么您可以使用 frexp 将数字分解为有效数(带符号)和指数,您可以使用 ldexp 重新组合它:

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

double bar = ldexp(I, E-53);

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

甚至可以将 IE 打包到一个 int64_t 中,如果你不想麻烦的话。

关于c - 是否可以保真地将浮点 double 往返到两位十进制整数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16543832/

相关文章:

线性代数的 C 库

algorithm - IEEE754 单精度 - 表示数字一半的通用算法

c++ - 为什么 IEEE-754 float 不能在平台之间交换?

c - 使用浮点二进制的算术运算 "0b"

C多个文件,打印数组的段错误

c - 汇编语言和c语言——文件大小的比较

在循环中创建带有数组的管道

c - 从二进制可见性图制作羽化可见性图

java - 重新审视 IEEE-754 double (64 位浮点)与长整型(64 位整数)

math - 理论上最小的浮点格式是什么?