【C/C++】c语言中数值计算范围注意事项

前几天用到这个式子

 powerCosum = (abs(iqactual_filter)) *  KeMotor * speedinrpm_abs_filte * 658/600000; 

来计算功率
powerCosum——s16,signed short int范围(0-800)
iqactual_filter——s16,signed short int,范围(0-20)
KeMotor——u8,unsigned char,范围(70-34)
speedinrpm_abs_filters——u16,unsigned short int,范围(0-700)

当speedinrpm_abs_filters大于580左右时,计算出来的powerCosum会变成负值。推断应该是数据越界造成的,但关键是数据为什么会越界??

换成下式后,计算正常
powerCosum = (u32) (abs(iqactual_filter)) * KeMotor * speedinrpm_abs_filte * 658/600000;
数据越界问题
(1) 数据类型越界
unsigned char a,a数据范围为 0-255,范围以外的都会发生错误
例如:

	a = 300;				//300>255,所以256时变为0,300则为44
	printf("%d\n", a);    // 输出44
其他数据类型类似;

解决办法:通常是换用数值范围更大的数据类型。比如上边 更换 unsigned char 为 unsigned short 

(2) 计算过程越界

首先先来个简单的程序,设定最后计算出来的结果不变(254),不断增大中间过程的值。

	unsigned char a, b, c, d;
	a = 254, b = 254,c=60;
	d = (a + b)*100/200;      //2个0,254
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*10000/20000;      //4个0,254
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*1000000/2000000;      //6个0,254
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*10000000/20000000;      //7个0,39  错误
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*10000000/20000000;      //8个0,253  错误
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*10000000/20000000;      //9个0,0  错误
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*100000000/200000000;      //10个0,254  
	printf("%d\n",d);

	a = 254, b = 254,c=60;
	d = (a + b)*1000000000/2000000000;      //11个0,254  
	printf("%d\n",d);

可以看出
在 d = (a + b)*10000000/20000000; 时开始出错
(a + b)*10000000 = 5 080 000 000,而unsigned int 型数据类型范围为0-4 294 967 295。中间过程的值大于unsigned int最大值。
(5 080 000 000 - 4 294 967 295)/20000000 = 39.

所以c语言运算过程中的值,默认最大为4 294 967 295.

那么怎么解决运算过程中的数据越界呢?

方法1:减小中间值。
对于固定的中间值,比如上面的10000000/20000000 直接简化为1/2.
方法2:增大数据上限
利用强制类型转换把运算过程值上限提高。 d =(unsigned long long) (a + b)*1000000000/2000000000; // 254

———————————————————————————————————————————————————————
默认上限都是4 294 967 295吗?
功率计算公式中,家了(u32)正常。如果按照默认是u32,那么不加也应该是正常的啊???

你可能感兴趣的:(c/c++)