0

我想将一对整数编码为双精度数。例如说我想传递一个函数:

foo(int a, int b)

但相反,我只想要一个双精度来表示两个整数(即):

foo(double aAndB)

目前,我通过在小数点的任一侧设置一个 int(即 10 和 15 将变为 10.15)然后将其转换为 stringstream 标记并提取这两个数字来做到这一点。

然而,当涉及到像 10 和 10 这样的数字时,这有一个明显的缺陷,即它变成了 10.1。

有没有办法通过一些棘手的数学方法来做到这一点,以便我可以传递一个代表 2 个整数的双精度函数?

谢谢。

4

6 回答 6

5

由于(通常)一个 double 有 64 位,每个 int 有 32 位,你会认为你可以直接将这些位存储到 double 中,例如:

int32_t i1 = rand();
int32_t i2 = rand();
int64_t x = (((int64_t)i1)<<32) | ((int64_t)i2);
double theDouble;
memcpy(&theDouble, &x, sizeof(theDouble));

......并且这样做“几乎有效”。也就是说,它适用于 i1 和 i2 的许多可能值——但并非适用于所有值。特别是,对于 IEEE754 浮点格式,指数位设置为 0x7ff 的任何值都将被视为指示“NaN”,并且浮点硬件可以(并且确实)将不同的 NaN 等效位模式转换回其首选将 double 作为参数传递时的 NaN 位模式等。

正因为如此,在大多数情况下,将两个 32 位整数填充到双精度中似乎是可行的,但是如果您使用所有可能的输入值对其进行测试,您会发现在某些情况下,这些值在它们停留在双精度中时会意外变异,并且当您再次解码它们时,它们会出现不同的值。

当然,您可以通过仅设置双精度的尾数位来解决此问题,但这只会为每个整数提供 26 位,因此您只能存储 +/- 33,554,432 左右的整数值。也许没关系,具体取决于您的用例。

我的建议是,找到一种不同的方式来做你想做的任何事情。将非浮点数据存储在浮点变量中是自找麻烦,特别是如果您希望您的代码完全可移植。

于 2012-05-25T06:44:55.470 回答
4

如果你很幸运并且 int 是 double 的一半,你可以像这样存储 int:

整数a = 10;
诠释 b = 20;
双 d;

*(int *)&d = a;
*((int *)&d + 1) = b;

int outa = *((int *)&d);
int outb = *(((int *)&d) + 1);
printf("%d %d\n", outa, outb);

这通常不起作用/可移植性。如果 double 和 int 具有相同的位数,那么您想要的就是不可能的。

于 2012-05-25T06:34:20.563 回答
3

double 可以精确地表示最多 53 位的整数。如果你想保存一个 26 位和一个 27 位整数,这很容易:double combined = bits27*67108864.0 + bits26;

请注意,67108864 是 2^26。

于 2012-05-25T06:33:07.660 回答
1

尝试像这样定义一个联合:

struct two_int {
    int a;
    int b;
};

union encoding {
    struct two_int a;
    double c;
};

但是这样做可能会带来便携性问题。请仔细检查这种方法是否适合您的情况。

于 2012-05-25T06:35:08.937 回答
1

您可以通过使用二进制掩码并从“双”中提取信息来做到这一点。

例如:

double encode(int a, int b)
{
    double d = 0;
    d = d | a; 
    d = d | (b << 8);
    return d;
}

double decode(double d)
{
    a = d & 0xFF;
    b = (d >> 8) & 0xFF;
}

在编码部分,a 将在双变量 d 的低 8 位中,b 将在 d 的高 8 位中。

于 2012-05-25T06:35:13.720 回答
0

如果你总是将两个整数传递给这个参数,那么传递一个双精度整数是没有意义的。而是将两个整数作为单独的整数传递,或者将它们包装在一个结构中。

你这样做的方式让你没有机会检测真正的双精度和两个整数之间的差异。因此,我得出结论,通过执行我上面描述的操作,您不会失去任何功能。

于 2012-05-25T06:36:46.283 回答