我需要使用套接字传输double值(例如-47.1235648)。由于我有很多平台,我必须转换为网络字节顺序,以确保所有目的的正确结束....但这个转换不接受double,只是整数和短,所以我&#39 ; m'切割'我的双重转换为两个整数,如下所示:
double lat = -47.848945;
int a;
int b;
a = (int)lat;
b = (int)(lat+1);
现在,我需要在另一端恢复这个,但是尽可能使用最小的计算(我看到一些使用POW的例子,但看起来像pow使用了很多资源,我不确定) 。有没有办法尽可能简单地加入这个,比如位操作?
答案 0 :(得分:2)
你的代码毫无意义。
典型的方法是使用memcpy()
:
const double lat = -47.848945;
uint32_t ints[sizeof lat / sizeof (uint32_t)];
memcpy(ints, &lat, sizeof lat);
现在发送ints
的元素,它们只是32位无符号整数。
这当然是假设:
uint32_t
,即每字节字节数或使用字节序转换函数。double
格式(通常为IEEE-754)。double
值移动时,您可以以某种方式管理字节顺序要求(请参阅@JohnBollinger's answer)。我将你的问题解释为所有这些假设都是安全的,这可能有点过头了。只要它被接受,我就无法删除这个答案。
答案 1 :(得分:2)
您考虑到数字表示方面的差异,这很好,但您对如何处理此问题的想法并不可靠。
让我们假设所涉及的每台机器都使用64位IEEE-754格式进行double
表示。 (这已经是一个潜在的失败点,但在实践中你可能不必担心那里的失败。)你似乎假设机器的字节顺序' double
将以一致的方式映射到整数的字节顺序,但这不是一个安全的假设。此外,即使这个假设成立,你也需要完全正确的映射方案才能使你的方案发挥作用,这不仅是不安全的假设,而且非常合理地不会是你实际看到的。
为了论证,假设具有大端整数的机器A想要将double
值传递给机器B,机器B具有小端整数。进一步假设在B上,其double
表示的字节顺序与A上的顺序完全相反(再次,这是不安全的假设)。因此,如果在A上,该double的字节按顺序
S T U V W X Y Z
然后我们希望它们按顺序
Z Y X W V U T S
在B.你的方法是将原始分割为一对(STUV,WXYZ),以保值的方式转移对(get,VUTS,ZYXW),然后将它们重新组合在一起得到..呃哦......
V U T S Z Y X W
。不要想象通过先交换这对来解决这个问题。这并不能满足您的目的,因为如果两个通信机器具有相同的字节顺序,您必须避免这样的交换,并且您无法从8字节中知道是否需要这样的交换。因此,即使我们做出了我们知道不安全的简化假设,您的策略也不足以完成任务。
替代方案包括:
frexp()
和ldexp()
函数可以帮助编码和解码此类表示。答案 2 :(得分:2)
我需要使用套接字传输double值(例如-47.1235648)。
如果平台对double
有可能不同的编码,那么发送double
的位模式是个问题。如果代码需要可移植性,则需要小于“仅复制位”的方法。另一种选择如下。
如果平台始终具有相同的double
格式,则只需复制n
位。例如:@Rishikesh Raje
详细地说,OP的问题只是松散定义。在许多平台上,double
是binary64但是double
代表约2 64 不同的值完全。 -47.1235648和-47.848945都不是其中之一。因此OP可能没有强烈的精确度。
“尽可能使用最小计算”意味着最少的代码,通常是最短的时间。对于速度,任何解决方案都应评为order of complexity 和code profiling。
便携式方法是通过字符串发送。这种方法首先解决了正确性和最佳可能的精度。它会删除字节序问题,因为数据是通过字符串发送的,并且在发送数据时没有精度/范围损失。如果使用相同的double
格式,接收方将完全重新构建double
。使用不同的double
计算机,它具有良好的字符串表示,可以尽其所能。
// some ample sized buffer
#define N (sizeof(double)*CHAR_BIT)
double x = foo();
char buf[N];
#if FLT_RADIX == 10
// Rare based 10 platforms
// If macro DBL_DECIMAL_DIG not available, use (DBL_DIG+3)
sprintf(buf, "%.*e", DBL_DECIMAL_DIG-1, x);
#else
// print mantissa in hexadecimal notation with power-of-2 exponent
sprintf(buf, "%a", x);
#endif
bar_send_string(buf);
重新构建double
char *s = foo_get_string();
double y;
// %f decode strings in decimal(f), exponential(e) or hexadecimal/exponential notation(a)
if (sscanf(s, "%f", &y) != 1) Handle_Error(s);
else use(y);
答案 3 :(得分:1)
更好的想法是将双重直接发送为网络字节顺序中的8个字节。
您可以使用联合
typedef union
{
double a;
uint8_t bytes[8];
} DoubleUnionType;
DoubleUnionType DoubleUnion;
//Assign the double by
DoubleUnion.a = -47.848945;
然后你可以进行网络字节顺序转换功能
void htonfl(uint8_t *out, uint8_t *in)
{
#if LITTLE_ENDIAN // Use macro name as per architecture
out[0] = in[7];
out[1] = in[6];
out[2] = in[5];
out[3] = in[4];
out[4] = in[3];
out[5] = in[2];
out[6] = in[1];
out[7] = in[0];
#else
memcpy (out, in, 8);
#endif
}
在发送前和接收后调用此功能。