将两个整数加入一个双精度数

时间:2017-03-30 12:59:32

标签: c

我需要使用套接字传输double值(例如-47.1235648)。由于我有很多平台,我必须转换为网络字节顺序,以确保所有目的的正确结束....但这个转换不接受double,只是整数和短,所以我&#39 ; m'切割'我的双重转换为两个整数,如下所示:

double lat = -47.848945;
int a;
int b;
a = (int)lat;
b = (int)(lat+1);

现在,我需要在另一端恢复这个,但是尽可能使用最小的计算(我看到一些使用POW的例子,但看起来像pow使用了很多资源,我不确定) 。有没有办法尽可能简单地加入这个,比如位操作?

4 个答案:

答案 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的问题只是松散定义。在许多平台上,doublebinary64但是不需要由C. 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  
}

在发送前和接收后调用此功能。