编写程序解决问题,往往离不开运算,从最简单的数学运算,到复杂的幂、开方、三角、对数,C++都能轻松应对。
一、基本数学运算
数学中最基本的是加(+)、减(-)、乘(×)、除(÷)四则运算,C++中有加(+)、减(-)、乘(*)、除(/)、模(%)五则基本运算。下面通过几个示例程序加以说明:
#include<iostream> using namespace std; int main() { cout<<123+456<<endl; //两个整数相加 cout<<123.456+456.789<<endl; //两个小数(浮点数)相加 cout<<123-456<<endl; //两个整数相减 cout<<123.456-456.789<<endl; //两个小数(浮点数)相减 cout<<-789<<endl; //-表示负数 cout<<-(-789)<<endl; //-也能表示取反 return 0; }
编写并运行上面的程序,观察运行结果,可知用cout输出一个计算表达式,运行时会先计算结果,再将结果输出。再来看下面这段程序:
#include<iostream> using namespace std; int main() { cout<<123*456<<endl; //注意乘号是米字乘*,不能写成叉乘×,也不能写成点乘· cout<<123*-456<<endl; cout<<12.34*56.78<<endl; cout<<123.456*456.789<<endl; cout<<1234567.45*456.78<<endl; cout<<0.00123*0.004567<<endl; cout<<123.000<<endl; cout<<123.9999<<endl; return 0; }
在Dev C++中上面程序运行结果如下:
56088 -56088 700.665 56393.3 5.63926e+008 5.61741e-006 123 124
后面6行输出有点费解,和计算器算出来的结果不一致,原因是:cout输出小数(浮点数)时,默认最多保留6位有效数字(第3行输出700.665
,第4行输出56393.3
的原因);如果数字太大或太小(绝对值超过\(10^6\)或者绝对值小于\(0.00001\)),会按照科学计算法的方式输出(所以第5行输出5.63926e+008
、第6行输出5.61741e-006
,5.63926e+008
表示\(5.63926 \times 10^8\),5.61741e-006
表示\(5.61741 \times 10^{-6}\))。cout输出浮点数会忽略掉小数末尾的0,所以第7行输出123,第8行保留6位有效数字并忽略掉小数末尾的0输出124。
也可以指定浮点数的输出格式,例如下面的程序指定浮点数保留5位小数输出(注意引入了一个新的头文件#include<iomanip>
):
#include<iostream> #include<iomanip> //这个头文件不能少 using namespace std; int main() { //设置输出小数(浮点数)时保留5位小数 //固定写法,保留其它小数位数修改setprecision()括号中的数字即可 cout<<fixed<<setprecision(5); //设置后,后面输出都会遵循输出规则 cout<<12.34*56.78<<endl; cout<<123.456*456.789<<endl; cout<<1234567.45*456.78<<endl; cout<<0.000009<<endl; cout<<123<<endl; //输出123,setprecision设置的保留小数位数对整数无效 return 0; }
程序输出结果如下:
700.66520 56393.34278 563925719.81100 0.00001 123
分析结果可知,保留小数位数的同时还自动实现了“四舍五入”!小结一下:引入iomanip头文件后,使用cout输出浮点数时可以通过cout<<fixed<<setprecision(要保留的小数位数);
设置小数位数,保留小数位数时会自动实现“四舍五入”。其实这个保留小数位数的方法过于复杂,不好记忆,后面会介绍简单的方法。
再来看除法运算和模运算(模运算就是求余数):
#include<iostream> using namespace std; int main() { cout<<5/2<<endl; // 整数/整数,注意除号必须用/ cout<<4/2<<endl; // 整数/整数 cout<<5.0/2<<endl; // 浮点数/整数 cout<<5.0/2.0<<endl; // 浮点数/浮点数 cout<<5%2<<endl; // %是模运算,这里计算5除以2的余数 return 0; }
程序输出结果如下:
2 2 2.5 2.5 1
分析运算结果,会发现第1行 5/2
输出2
与数学运算结果不一致。C++中的除法运算有一个特点,如果是 整数/整数
,那么结果是一个整数(小数部分全部被舍弃,结果是除法的商),但是被除数或者除数只要有一个是浮点数,那么结果就是浮点数。
注意模运算仅限于 整数%整数
,否则会出现编译错误!
小结一下:
整数/整数
,结果是除法的商;- 浮点数参与除法(被除数数和除数至少有一个是浮点数),结果是浮点数;
整数%整数
结果是除法的余数。
最后,和数学混合运算一样,C++复杂的运算也涉及到运算优先级的问题:
#include<iostream> using namespace std; int main() { cout<<1+2*3<<endl; cout<<(1+2)*3<<endl; return 0; }
大家自行编辑程序并运行,通过分析结果可知:C++中也是优先计算乘除(包括模运算),再计算加减;如果有小括号,那优先计算小括号中的内容。这和数学混合运算一致,有一点不同的是,不管多少层括号,都用小括号!
二、使用数学函数
来看一个数学问题,计算直角边为60和91的直角三角形斜边长。已知斜边计算公式 \(c = \sqrt{a^2+b^2}\),这里平方和还容易得到:60*60+91*91
,但是接下来的开平方是C++的五则基本运算无法实现的!
好在C++中已经内置了不少函数(目前可以把C++的函数理解成可以实现特定运算的工具),能够完成开平方、幂、三角、对数等数学计算。要解决上述问题,我们可以用到两个函数——pow幂函数和sqrt开平方函数,先编写一个程序来测试一下两个函数的功能(注意需要通过#include<cmath>
引入cmath头文件):
#include<iostream> #include<cmath> //需要引入cmath头文件 using namespace std; int main() { cout<<pow(60,2)<<endl; //pow(60,2)计算60的2次方,然后cout输出结果 cout<<sqrt(9)<<endl; //sqrt(9)计算9开平方,然后cout输出结果 return 0; }
计算斜边的公式 \(\sqrt{60^2+91^2}\),对应的C++代码可以写成:sqrt( pow(60,2) + pow(91,2) )
,这个复杂的计算表达式会首先计算sqrt()括号中的内容pow(60,2) + pow(91,2)
,这是一个加法运算,那么会先后计算出pow(60,2)
和pow(91,2)
的值,然后相加的结果作为sqrt函数开平方的参数。最终程序代码如下:
#include<iostream> #include<cmath> //需要引入cmath头文件 using namespace std; int main() { cout<<sqrt(pow(60,2)+pow(91,2))<<endl; return 0; }
其实pow函数可以计算小数次方,由数学知识可知 sqrt(9)
和 pow(9,0.5)
是等效的。那么还可以只使用pow函数解决问题:
#include<iostream> #include<cmath> //需要引入cmath头文件 using namespace std; int main() { cout<<pow(pow(60,2)+pow(91,2),0.5)<<endl; return 0; }
这里将cmath头文件中常用的函数整理如下表:
函数调用方法 | 举例 | 说明 | ||
\(pow(x,y)\) | \(pow(3,2)\) \(pow(3,0.5)\) \(pow(2.5,7.8)\) | 计算 \(x^y\),结果是浮点数 | ||
\(sqrt(x)\) | \(sqrt(2)\) \(sqrt(2.5)\) | 计算 \(\sqrt{x}\),结果是浮点数 | ||
\(abs(x)\) | \(abs(-10)\) | 计算\(x\)的绝对值\(|x|\)。如果\(x\)是整数,结果是整数;如果\(x\)是浮点数,结果是浮点数 | ||
\(fabs(x)\) | \(fabs(-10)\) \(fabs(-2.5)\) | 计算\(x\)的绝对值\(|x|\),不论\(x\)是整数还是浮点数,结果都是浮点数 | ||
\(ceil(x)\) | \(ceil(2.1)\) \(ceil(-2.9)\) | 计算大于或等于\(x\)的最小整数(向上取整),结果是小数部分为0的浮点数 | ||
\(floor(x)\) | \(floor(2.9)\) \(floor(-2.1)\) | 计算小于或等于\(x\)的最大整数(向下取整),结果是小数部分为0的浮点数 | ||
\(sin(x)\) \(cos(x)\) | \(sin(3.14159)\) \(cos(3.14159/2)\) | 计算三角函数正弦\(sin(x)\)、余弦\(cos(x)\)值 \(x\)是弧度角度 | ||
\(exp(x)\) | \(exp(1)\) | 计算\(e^x\),\(e\)是自然常数 | ||
\(log(x)\) | \(log(10)\) \(log(exp(1))\) | 计算\(x\)的自然对数\(\ln{x}\)(即\(\log_{e}{x}\)) | ||
\(log2(x)\) | \(log2(2)\) \(log2(1024)\) | 计算以2为底\(x\)的对数\(\log_{2}{x}\) | ||
\(log10(x)\) | \(log10(10)\) \(log10(100)\) | 计算以10为底\(x\)的对数\(\log_{10}{x}\) |
建议自己编写程序测试一下上面cmath中的常用函数。
此外algorithm头文件下还有\(max、min\)两个常用函数:
函数调用方法 | 举例 | 说明 |
\(max(a,b)\) | \(max(3,5)\) \(max(0.1,0.5)\) | 计算\(a、b\)的最大值 \(a、b\)的类型必须相同,例如全是整数或者全是浮点数 |
\(min(a,b)\) | \(min(3,5)\) \(min(0.1,0.5)\) | 计算\(a、b\)的最小值 \(a、b\)的类型必须相同,例如全是整数或者全是浮点数 |
三、浮点数的特点
程序设计语言中一般将小数称为浮点数(这个名称是根据浮点数在计算机内部存储方式得来的),来测试下面的程序:
#include<iostream> #include<cmath> using namespace std; int main() { cout<<ceil(1.01)<<endl; cout<<ceil(1.000000000000001)<<endl; cout<<ceil(1.0000000000000001); return 0; }
ceil是向上取值,预期应该都输出2,但是实际运行结果如下:
2 2 1
感觉奇怪吧!注意:C++中的浮点数只能保证在一定的有效数字范围内是可靠的,超过这个范围就只能认为是约等于,不是精确相等!
cout<<1.0000000000000001;
会输出1
,后面的.0000000000000001超出了可靠的有效数字范围,C++处理时这部分被丢弃了!此时cout<<ceil(1.0000000000000001);
其实就相当于 cout<<ceil(1);