浮點數移位操作和類型轉換問題


  • 今天遇到了一些坑,之前自己用移位后的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聯合體


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM