zoukankan      html  css  js  c++  java
  • 浮点数移位操作和类型转换问题

    • 今天遇到了一些坑,之前自己用移位后的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
    ", 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{-bpmsqrt{b^2-4ac}}{2a} ]

    (x=frac{-bpmsqrt{b^2-4ac}}{2a})

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

  • 相关阅读:
    Android TextView里显示两种颜色
    Android 命令管理项目
    ANT build.xml文件详解
    Android Camera进行拍照
    Android 4.2以上的手机USB调试设置
    Android MediaPlayer和SurfaceView播放视频
    Android VideoView播放视频
    Android MediaRecorder录制音频
    Android Handler消息传递机制
    Android SurfaceView
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/6656803.html
Copyright © 2011-2022 走看看