Fork me on GitHub

浮点数移位操作和类型转换问题

  • 今天遇到了一些坑,之前自己用移位后的int结果不对;然后改为原始的double就可以;今天硬着头皮才知道自己犯了很多错误!
    之前的代码:Mat[]为double类型
y0 = (RegionInfoList[i].minx*Mat[3] - RegionInfoList[i].miny*Mat[0] - (Mat[2] * Mat[3] - Mat[0] * Mat[5])) / (Mat[1] * Mat[3] - Mat[0] * Mat[4]);

x0 = (RegionInfoList[i].minx*Mat[4] - RegionInfoList[i].miny*Mat[1] - (Mat[2] * Mat[4] - Mat[1] * Mat[5])) / (Mat[0] * Mat[4] - Mat[1] * Mat[3]);
y1 = (RegionInfoList[i].maxx*Mat[3] - RegionInfoList[i].maxy*Mat[0] - (Mat[2] * Mat[3] - Mat[0] * Mat[5])) / (Mat[1] * Mat[3] - Mat[0] * Mat[4]);
x1 = (RegionInfoList[i].maxx*Mat[4] - RegionInfoList[i].maxy*Mat[1] - (Mat[2] * Mat[4] - Mat[1] * Mat[5])) / (Mat[0] * Mat[4] - Mat[1] * Mat[3]);

需要Mat[]改为左移16位的int类型;先想直接将Mat[]的每个元素(Mat[i]>>16)就行了,但是这样做跟直接用double类型的没有区别。而且这样做有错误!最多到1.0

	int a = 66519;
	double b = a >> 16;
	printf("移位结果:%lf\n", b); //输出1.000000

然后查C语言浮点数不能进行移位操作

  • 有符号整数的移位操作
  • 浮点数的移位操作
  • 移位操作VS使用联合体

无符号整数的移位操作

C语言中,有符号数据的移位操作和无符号的移位操作不同,无符号的移位操作为逻辑移位,即高位舍弃,低位补0;高位补0,低位舍弃。有符号的整数类型的移位操作为算数移位,也就是最高位保持不变,负数高位移位后还是保持“1”,正数移位后还是保持“0”,而其他位和逻辑移位一样。

浮点数的移位操作

C语言不支持浮点数的移位操作,浮点数的存储和整型数的存储不同,并不是直接将数值表示成二进制形式存储,存储的方式在下表呈现,具体的在这里不多说,浮点数直接移位后基本没有什么意义,但是有时候还是需要进行移位操作,比如使用串口/IIC/CAN等通信时,需要将数据一字节一字节的发送,对于浮点数来说,就需要将浮点数分解成字节,这样常用的有两种方法,一是利用联合体的特点将浮点数分解,二是利用移位操作,移位操作需要一些技巧。
浮点数不能直接使用移位操作,整型可以,所以将浮点数转化为整型数进行移位是可行的,但是这里的类型转化不是类似(int)a这样的强制类型转换,而是将存储整型的数据内存的解释规则转化为整型,比如进行如下操作:

float a;
uint32_t *data = (uint32_t *)&a;

经过这样的操作后,保存数据a的内存,就可以使用data或者(uint32_t )&a解释成整型,并且对data或者(uint32_t )&a进行移位操作把浮点数分解为单个字节并且不改变每一位的值。

移位操作VS使用联合体

下面的两段代码都可以将浮点数分解为单字节并进行操作,比较来看,在将数据(并不限制为浮点数)分解为字节倍数的类型时,联合体的操作更加简单易懂,但是移位操作没有这一限制,比使用联合体灵活,但也相对复杂,比较来看,各有千秋。

//浮点数的移位操作
#include "stdint.h"
#include "stdio.h"

int main(void)
{
    double  val = 48646.1123;
    double  Result = 0;

    uint8_t data2[8];


    for (int i = 0;i < 8;i++) {
        data2[i] = ((*(uint64_t *)&val) >> (8 * i)) & 0xff;
    }

    for (int i = 0;i < 8;i++) {
        (*(uint64_t *)&Result) = (*(uint64_t *)&Result) << 8 | data2[7 - i];
    }

    printf("%f", Result);
    system("pause");
}

//使用联合体达到移位操作效果
#include "stdio.h"
#include "stdint.h"
#include "string.h"
int main(void)
{
	union
	{
		uint8_t data[8];
		double  val;
	}test, test2;
	double x = 5.1;
	double re;
	int i;

	test.val = x;
	for (i = 0; i < 8; i++)
	{
		test2.data[i] = test.data[i];
	}
	re = test2.val;


	printf("%f", re);
}

** 浮点数移位转化为字节操作**

最后处理方法

本身等式就是上下除的形式,然后可以抵消;遇到的坑就是(Mat[2] * (long long)Mat[3])这些地方都要用强制类型转换。然后强制类型转换需要在运算前进行,计算后转换是没有效果的


//注意溢出处理
y0 = (((long long)(RegionInfoList[i].minx*Mat[3] - RegionInfoList[i].miny*Mat[0]) << 16) - ((Mat[2] * (long long)Mat[3]) - (Mat[0] * (long long)Mat[5]))) / ((Mat[1] * (long long)Mat[3]) - (Mat[0] * (long long)Mat[4]));
x0 = (((long long)(RegionInfoList[i].minx*Mat[4] - RegionInfoList[i].miny*Mat[1]) << 16) - ((Mat[2] * (long long)Mat[4]) - (Mat[1] * (long long)Mat[5]))) / ((Mat[0] * (long long)Mat[4]) - (Mat[1] * (long long)Mat[3]));
y1 = (((long long)(RegionInfoList[i].maxx*Mat[3] - RegionInfoList[i].maxy*Mat[0]) << 16) - ((Mat[2] * (long long)Mat[3]) - (Mat[0] * (long long)Mat[5]))) / ((Mat[1] * (long long)Mat[3]) - (Mat[0] * (long long)Mat[4]));
x1 = (((long long)(RegionInfoList[i].maxx*Mat[4] - RegionInfoList[i].maxy*Mat[1]) << 16) - ((Mat[2] * (long long)Mat[4]) - (Mat[1] * (long long)Mat[5]))) / ((Mat[0] * (long long)Mat[4]) - (Mat[1] * (long long)Mat[3]));

最后看看各种类型的范围:

速查表:
char -128 ~ +127 (1 Byte)
short -32767 ~ + 32768 (2 Bytes)
unsigned short 0 ~ 65535 (2 Bytes)
int -2147483648 ~ +2147483647 (4 Bytes)
unsigned int 0 ~ 4294967295 (4 Bytes)
long == int
long long -9223372036854775808 ~ +9223372036854775807 (8 Bytes)
double 1.7 * 10^308 (8 Bytes)
unsigned int 0~4294967295
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615

  • 实验一下支持Latex公式插入:

\[x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} \]

\(x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}\)

C浮点数之移位操作VS联合体

posted @ 2017-04-01 17:14  ranjiewen  阅读(7905)  评论(0编辑  收藏  举报