将多个整数编码为双精度

我想在一个double中编码一对ints。例如,我想传递一个函数:

foo(int a, int b)

但是我只需要一个双精度来表示两个整数(即):

foo(double aAndB)

目前我正在通过在小数点的任一侧有一个int(即10和15将变为10.15)然后将其转换为stringstream令牌并提取这两个数字。

然而,这对于10和10这样的数字来说有明显的缺陷,即它变成了10.1。

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

谢谢。

0
额外
意见: 1
@Ben:这并不有趣。这只是一个位数和一些指针操作的问题。或者你使用联盟。如果你需要这样做,那简直是糟糕的设计。
额外 作者 Tobias Langner,
你想用这个做什么?由于您有用编码标记的问题,因此我假设您在某个时刻想要解码double以获取两个ints。在这种情况下,你希望编码是无损的吗?
额外 作者 Vikas,
10.1 有什么问题?我的意思是,如果你要写它,如果有人告诉你写10和100,你也不会写10.10。
额外 作者 RedX,
然后问题是如何区分 int(10).int(1)int(10).int(10)int(10) .int(100)int(10).int(001)?另一种要问的方法是:小数位数可能有多少?
额外 作者 RedX,
@Vikas对两者都是
额外 作者 Fantastic Mr Fox,
我正在考虑通过将整数编码为双精度的二进制数来实现
额外 作者 Fantastic Mr Fox,
@RedX但是我希望我的函数能够使用双精度并将其分割回原来的2个整数。如果我得到1而不是10,那么程序将无法工作。
额外 作者 Fantastic Mr Fox,
@Paolo 1.它的一个有趣的问题。 2.因为我有一个工厂方法的抽象类型,只需要双打,我需要传递2个整数
额外 作者 Fantastic Mr Fox,
@TobiasLangner这是你的看法,我只是试图出于兴趣,看看它是否可以完成。为什么这么消极?
额外 作者 Fantastic Mr Fox,
对于那些试图主宰这种方法的人来说,我已经以另一种方式实施了,我只想看看这种方式是否可行。尽量不要一哄而散。另外请注意,感谢所有回答良好的人。
额外 作者 Fantastic Mr Fox,
你甚至不能在这里传递0和1,因为0.1不能完全表示。
额外 作者 David Heffernan,
你为什么要那样做?
额外 作者 Paolo Brandoli,

6 答案

由于(通常)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位整数填充为double将会显示工作,但是如果使用所有可能的输入值对其进行测试,则会发现一些情况,其中的值在双重停留期间意外发生变化,当你再次解码它们时出现不同的值。

当然,你可以通过小心设置双精度的尾数位来解决这个问题,但是这只会给你每个整数26位,所以你只能存储+/- 33,554,432左右的整数值。也许这没关系,取决于你的用例。

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

5
额外

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

int a = 10;
int b = 20;
double 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具有相同的比特数,那么你想要的是不可能的。

4
额外
这将在32位上工作 - 最有可能的。但是,作为用户85509它不是便携式。但即使将自己限制为32位整数类型(有一些标题有它们) - 如果您需要这样做,这是设计不好的标志。
额外 作者 Tobias Langner,

A double can exactly represent an integer up to 53 bits. If you want to hold a 26-bit and a 27-bit integer, it's very easy: double combined = bits27*67108864.0 + bits26;

请注意,67108864是2 ^ 26。

3
额外

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

struct two_int {
    int a;
    int b;
};

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

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

1
额外

您可以使用二进制掩码并从“double”中提取信息。

例如:

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位。

1
额外

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

你这样做的方式让你没有机会检测到真正的双精度和两精度之间的差异。所以我得出结论,你会失去任何功能,做我上面描述的。

0
额外
如果他能控制工厂界面,他应该这样做。
额外 作者 RedX,
这不是对这个问题的回答。感谢您的建议,但我现在只是在尝试某种方式。
额外 作者 Fantastic Mr Fox,
其实它既不是,如果你阅读这个问题的评论,我已经实现了另一种方式,我总是有选择。我只想知道是否有可能。我的道歉,但你的答案不是对这个问题的答案,而只是一个评论。
额外 作者 Fantastic Mr Fox,
@Ben这可能不是你想听到的答案,但它可能是你的问题的解决方案
额外 作者 David Heffernan,