将字节数组转换为双精度浮点数 - C

8

我正在尝试从一个包含16个元素的字节数组中获取数值(double),如下:

unsigned char input[16];
double output;
...
double a  = input[0];
distance = a;
for (i=1;i<16;i++){
    a = input[i] << 8*i;
    output += a;
}

但是它没有起作用。 似乎临时变量只能存储32位左移操作的结果,因为进行4次8位左移操作后,它就会溢出。

我知道我可以使用类似于

a = input[i] * pow(2,8*i);

但是,出于好奇心,我想知道是否可以使用移位运算符来解决这个问题...


你没有说清楚"input[16]"代表的是什么。它是一个128位的整数值,还是其他什么? - Roddy
1
你是否将“input”中的数字以128位无符号整数的形式存储? - Adrian Panasiuk
@Roddy:从他的算法来看,这些字符似乎是一个15次多项式(以256为底)中的系数。(@paolo_,这样对吗?) - xtofl
如Adrian P所说,input[16]向量是我想要表示为128位无符号整数的一系列比特序列。 - paolo_
7个回答

4

编辑:如果没有类似于__int128这样的东西,这将无法运行(请参见评论)。

a = input[i] << 8*i;

表达式input[i]被提升为int6.3.1.1),在您的计算机上是32位。为了克服这个问题,左操作数必须是64位,就像这样:

a = (1L * input[i]) << 8*i;

或者

a = (long long unsigned) input[i] << 8*i;

还要记住字节序


1
这个循环似乎在尝试将一个128位的值转换成双精度浮点数,所以当他尝试对i>=9部分执行(<< 8*i)时,这仍然会导致溢出,或者我漏掉了什么? - Falaina

4
这里的问题是,32位变量不能移动超过4 * 8次,也就是说,您的代码仅适用于4个字符。
您可以找到第一个有效字符,并使用Horner定律:anxn + an-1n-1 + ... = ((...( anx + an-1 ).x + an-2 ) . x + ... ) + a0,如下所示:
char coefficients[16] = { 0, 0, ..., 14, 15 };
int exponent=15;
double result = 0.;

for(int exponent = 15; exp >= 0; --exp ) {
   result *= 256.; // instead of <<8.
   result += coefficients[ exponent ];
}

2
简而言之,否,你不能像你的代码示例中展示的那样通过位移直接将一串字节转换为一个双精度浮点数。
byte是整型,double是浮点型(即不是整型),它们不具有按位兼容性(即你不能只通过位移将一堆字节的值转换为浮点型并期望得到相应的结果)。
1)假设字节数组是引用一个整数值的内存缓冲区,您应该能够通过位移将您的字节数组转换为128位整数,然后将得到的整数转换为双精度浮点数。请不要忘记,根据CPU架构,大小端问题可能会出现。
2)假设字节数组是包含128位长双精度值的内存缓冲区,并且假设没有大小端问题,您应该能够从字节数组中复制该值到长双精度值中。
union doubleOrByte {
    BYTE buffer[16];
    long double val;
} dOrb;
dOrb.val = 3.14159267;
long double newval = 0.0;

memcpy((void*)&newval, (void*)dOrb.buffer, sizeof(dOrb.buffer));

2
为什么不直接将数组转换为双指针呢?
unsigned char input[16];

double* pd = (double*)input;

for (int i=0; i<sizeof(input)/sizeof(double); ++i)
    cout << pd[i];

如果您需要修复字节序,那么在将字符数组强制转换为双精度数组之前,请使用STL reverse()函数反转该数组。

1
迄今为止最简单的解决方案! - Siyfion

1

我认为输入不是ASCII码,而是在缓冲区中的浮点数值。 - Dave Mooney
只有在输入为数字字符串格式时才相关,如果他将double转储到内存中,然后将其作为char数组加载,这将失败。 - DeusAduro

1
你是否正在尝试将数字的字符串表示转换为实际数字?如果是这样,C标准库中的atof函数将是你最好的朋友。

0
根据运算符优先级,右侧为基础。
a = input[i] << 8*i;

在转换为双精度浮点数之前,会先对其进行求值,因此您将input[i]向左移动8*i位,这将把结果存储在32位临时变量中,从而导致溢出。您可以尝试以下方法:

a = (long long unsigned int)input[i] << 8*i;

编辑:不确定您的系统上double类型的大小是多少,但在我的系统上它是8个字节,如果您的情况也是如此,那么输入数组的后半部分将永远不会被看到,因为移位操作将超出double类型的范围。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接