- 今天遇到了一些坑,之前自己用移位后的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}\)
