430 likes | 603 Views
计算方法上机基础篇. 应用于 C/C++ 语言程序设计. 华中科技大学数学与统计学院计算数学系. 科技楼南 836 室. 何南忠. QQ : 2121211. nzhe@163.com. http : //math.hust.edu.cn/he. 作者 : 从事于计算数学、高性能计算、 LBGK 及软件开发。. 2008-12. 第 01 章 数值、运算与程序. 数 – 分类. 数值计算中常用的 2 类. 整数 :. 无 小数点. ± 0 ± 1 ± 2 ± 3.
E N D
计算方法上机基础篇 应用于C/C++语言程序设计 华中科技大学数学与统计学院计算数学系 科技楼南836室 何南忠 QQ: 2121211 nzhe@163.com http://math.hust.edu.cn/he 作者: 从事于计算数学、高性能计算、LBGK及软件开发。 2008-12
数 – 分类 数值计算中常用的2类 整数: 无小数点 ±0 ±1±2±3 ... ±0.±0.1 ±1.±1.2 ±2.±2.3 ±3.... 实数: 有小数点 练习:
数 – 范围 整数: 内部表示为32位二进制整数 ±2147483647= ±231-1 实数: 内部表示为二个整数: ±0.999999999999999E±308 第一个整数表示小数部分, 第二个整数表示指数部分; 共占64个二进制位。 小数 指数 (小数54bits, 指数10bits)
数 – 精度 整数: 对小数取整; 超过范围取231的余数。 ±2147483647=±231-1 0.123456789012345E-10 实数: 15位后舍去; 超过范围则溢出报错。 小数部分15位 练习:
数 – 运算 + - * / 结果为整数 整数: 3 / 2 = 1 结果为实数 实数: 3.0 / 2.0 = 1.5 结果为实数 3.0 / 2 = 3 / 2.0 = 1.5 混合: 整数运算还有: % << >> & | ! ^ 取余数 左移 右移 按位与 按位或 按位反 按位异或 练习:
数–算术运算表达式 先*/后+-, 从左到右, 括号优先。 练习:
变量: 存贮一个数, 并能被取出来使用这个数 A, A1, B, B123, abc, ... 起名: 首字符为字母, 后面字母或数字 变量使用前要先定义, 定义用类型定义语句: 定义: 类型名 变量名; int A; 例: double B; 变量的使用包括存和取, 存用赋值语句: 使用: 变量名= 表达式; 而表达式中出现的变量名即为取变量的值。
程序: 语句序列 //先定义: int A; //名字为 A, 值的类型为 整数 double B; //名字为 B, 值的类型为 实数 //后使用: A = 10; //A: 10 B = 10.0; //B: 10.0 A = A + 1;//A: 11 B = A - B;//B: 1.0 ... 1. 类型定义语句 类型名 变量名; 2. 赋值语句 变量名 = 表达式; 取 存 赋值运算符 一行中//后面的为注释, 不起作用
程序: 完整结构 void main() { int A; double B; A = 10; B = 10.0; A = A + 1; B = A - B; int A; double B; A = 10; B = 10.0; A = A + 1; B = A - B; 执 打包 行 } 一个程序中有且仅有一个main函数; 程序从main函数中的第一行开始执行。 main函数:
键盘输入语句: 从键盘上输入一个或几个数到变量。 int A; scanf( ”%d”, &A ); ; -仅用于一条简单语句的结束 double B; scanf( ”%lf”, &B ); , -常用于分隔 int A, B; // 多个变量用,分隔之 double C,D; // 多个变量用,分隔之 scanf( ”%d%lf%d%lf”, &A, &C, &B, &D ); 地址列表 格式串 &变量名–表示该变量的地址
屏幕输出语句: 把字符串、数值显示到屏幕上。 printf( ”Hello, World!” ); 结果: Hello, World! int A; A = 100; printf( ”A =%d”, A+1 ); 结果: A =101 int A, B; double C, D; A = 100; B = A + 100; C = B + 100; D = C + 100; printf( ”A=%d,B=%d,C=%lf,D=%lf”,A+1, B+2, C+3, D+4 ); 值列表 格式串 一一对应 结果: A=101,B=202,C=303.0,D=404.0
程序1: 输出一个字符串的最简单程序。 #include <stdio.h> // 输入输出语句所在头文件 void main( ) { } printf( ”Hello, World!” ); 运行结果:
程序2: 变量赋一个值后输出该变量的值。 #include <stdio.h> void main() { int A; A = 100; printf( ”A = %d”, A ); } 运行结果:
程序3: 几个变量赋值后输出这几个变量的值。 #include <stdio.h> void main() { int A, B; double C, D; A = 100; B = A + 100; C = B + 100; D = C + 100; printf( ”A=%d,B=%d,C=%lf,D=%lf”, A, B, C, D ); } 运行结果:
程序4: 输入2个整数, 输出相加、相减、相乘和相除的结果。 #include <stdio.h> void main() { int A, B; scanf( ”%d%d”, &A, &B ); printf( ”%d + %d=%d”, A, B, A + B ); printf( ”%d - %d=%d”, A, B, A - B ); printf( ”%d * %d=%d”, A, B, A * B ); printf( ”%d / %d=%d”, A, B, A / B ); } 运行结果:
程序5: 输入2个实数, 输出相加、相减、相乘和相除的结果。 #include <stdio.h> void main() { int A, B; scanf( ”%lf%lf”, &A, &B ); printf( ”%lf + %lf=%lf”, A, B, A + B ); printf( ”%lf - %lf=%lf”, A, B, A - B ); printf( ”%lf * %lf=%lf”, A, B, A * B ); printf( ”%lf / %lf=%lf”, A, B, A / B ); } 运行结果:
程序6: 输入2个实数, 输出相加、相减、相乘和相除的结果的整数值。 #include <stdio.h> void main() { int A, B; scanf( ”%lf%lf”, &A, &B ); printf( ”%lf + %lf=%lf”, A, B, (int)(A + B ); printf( ”%lf - %lf=%lf”, A, B, (int)(A - B ); printf( ”%lf * %lf=%lf”, A, B, (int)(A * B ); printf( ”%lf / %lf=%lf”, A, B, (int)(A / B ); } 运行结果: (int)实数的结果为整数 (double)整数的结果为实数 这叫类型强制转换
程序7: 输入10个整数, 输出其和及平均值。 #include <stdio.h> void main() { int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9; int sum; printf( ”Enter 10 numbers: ”); scanf( ”%d%d%d%d%d%d%d%d%d”, &i0, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9); sum = i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9; printf( “sum is %d\n”, sum, x ); // \n – 换行符 printf( “average is %lf”, sum / 10.0 ); } 运行结果:
程序8: 输入1个实数, 输出其平方根。 #include <stdio.h> void main() { double a; double x; scanf( ”%lf”, &a ); x = a; x = ( x + a / x ) / 2; x = ( x + a / x ) / 2; x = ( x + a / x ) / 2; x = ( x + a / x ) / 2; x = ( x + a / x ) / 2; // 要准确, 则再重复100行 printf( “square root of %lf = %lf”, a, x ); } 运行结果:
程序9: 输入3个实数a、b、c, 输出ax2+bx+c=0的二个根。 #include <stdio.h> void main() { double a, b, c, d, d1; printf( ”Input a,b,c : ” ); scanf( ”%lf%lf%lf”, &a, &b, &c ); d = b*b – 4*a*c; d1 = d; d1 = ( d1 + d / d1 ) / 2; d1 = ( d1 + d / d1 ) / 2; d1 = ( d1 + d / d1 ) / 2; d1 = ( d1 + d / d1 ) / 2; d1 = ( d1 + d / d1 ) / 2; d1 = ( d1 + d / d1 ) / 2; printf( “x1 = %lf, x2 = %lf”, (-b+d1)/(2*a), (-b-d1)/(2*a) ); } 运行结果:
程序10: 输入3个实数a、b、c, 输出ax2+bx+c=0的二个根。 #include <stdio.h> #include <math.h> void main() { double a, b, c, d, d1; printf( ”Input a,b,c :” ); scanf( ”%lf%lf%lf”, &a, &b, &c ); d = b*b – 4*a*c; d1 = sqrt( d ); // 库函数, 求平方根 printf( “x1 = %lf, x2 = %lf”, (-b+d1)/(2*a), (-b-d1)/(2*a) ); } 运行结果:
程序11: 输入三角形的三条边的长度, 输出该三角形面积。 #include <stdio.h> #include <math.h> void main() { double a, b, c; double s, area; printf( ”Input a,b,c :” ); scanf( ”%lf%lf%lf”, &a, &b, &c ); s = a + b + c; area = sqrt( ( (s-a)+(s-b)+(s-c) ) / ( (s-a)*(s-b)*(s-c)) ); //? printf( “area = %lf”, area ); } 运行结果:
程序12: 输入二条直线, 求直线的交点。 #include <stdio.h> void main() { double a11, a12, b1; double a21, a22, b2; double x1, x2; printf( ”Input a11, a12, b1 : ” ); scanf( ”%lf%lf%lf”, &a11, &a12, &b1 ); printf( ”Input a21, a22, b2 : ” ); scanf( ”%lf%lf%lf”, &a21, &a22, &b2 ); x1 = ; // 自己填入 x2 = ; // 自己填入 printf( “x1 = %lf, x2 = %lf”, x1, x2 ); } 运行结果:
程序13: 输入一个0到90度之间的一个角度值, 输出其正弦值。 #include <stdio.h> void main() { double x; double sin_x; printf( ”Input angle x: ” ); scanf( ”%lf”, &x ); x = ( x / 360.0 ) * 2 * 3.14159265; // 角度变弧度 sin_x = x – x*x/2 + x*x*x*x/4/3/2 – x*x*x*x*x*x/6/5/4/3/2; // 想更准确? printf( “sin %d = %lf ”, x, sinx ); } 运行结果:
程序14: 输入一个0到90度之间的一个角度值, 输出其三角函数值。 #include <stdio.h> #include <math.h> // 数学函数库的头文件 void main() { double x; double sin_x; printf( ”Input angle x: ” ); scanf( ”%lf”, &x ); x = ( x / 360.0 ) * 2 * 3.14159265; // 角度变弧度 sin_x = sin(x); // 调库函数 printf( “sin %d = %lf ”, x, sin_x ); printf( “\ncos %d = %lf ”, x, cos(x) ); // 调库函数 printf( “\ncos %d = %lf ”, x, tan(x) ); // 调库函数 } 运行结果:
程序15: 一些数学库函数的调用。其它可查找数学函数表。 #include <stdio.h> #include <math.h> // 数学函数库的头文件 void main() { printf( “\n指数:%lf ”, exp( 2.302585) ); printf( “\n幂函数:%lf ”, pow( 2, 0.5 ) ); printf( “\n自然对数:%lf ”, log( 2 ) ); printf( “\n底10对数:%lf ”, log10( 2 ) ); } 运行结果:
程序16:输入半径, 输出圆的面积和周长。 #include <stdio.h> #define PI3.14159265// 符号定义语句 void main() { double r; printf( ”Input radus : ” ); scanf( ”%lf”, &r ); printf( ”%lf, %lf”, 2*PI*r, PI*r*r ); } 运行结果: 符号定义语句 #define符号名字符串 作用:编译起始时, 这一符号名 会先用后面的字符串替代。 注意:所有#开头的语句需独占一行。
程序17 问题: 求过二点的直线方程。 1. 输入: 二个点( x1, y1), ( x2, y2 ) 类型皆为 double 2. 输出: 系数a,b 使y=ax+b过上述二点; 类型皆为 double 3. 算法: x1a + b = y1 比划过程 x2a + b = y2 , 求a,b(用解二元一次方程组的方法)。 4. 代码 #inlcude <stdio.h> void main() { double x1, y1, x2, y2; // 这是存放输入的 double a, b; // 这时放结果的 scanf( ”%lf%lf%lf%lf%lf%lf”, &x1, &y1, &x2, &y2 ); a = ( y1 – y2 ) / ( x1 – x2 ); b = ( x1 * y2 – x2 * y1 ) / ( x1 – x2 ); printf( ”y=%lfx+%lf ”, a, b ); }
编程思路总结: 1. 先把外部的包装写上, 搭好框架; 2. 列出题目中已知的量和待求的量, 定好类型, 起好名字; 3. 思考需要引进哪些中间变量, 也定好类型, 起好名字; 4. 列出计算公式或算法, 必要时先画图示意; 5. 编程并运行验证。 临时量 输出量 输入量 加工 输入 输出 计算公式 算法描述 已知量 结果量 在编写任何一个程序时的思考图
输入 输出 加工 思想: 这一思想应贯穿你的每个程序设计中。 步骤: 问题分析 算法设计 程序编写 示例18 问题: 已知3点, 求圆心和半径。 不要查公式, 自己推导算法。 (以后的题目都是这样用自然语言简单描述, 自己把问题分析后具体化) 1. 输入: 三个点( x1, y1), ( x2, y2 ), ( x3, y3 ); 类型皆为 double 打草稿 2. 输出: 类型皆为 double 圆心( x0, y0 ), 半径 r ; 3. 算法: (先在草稿纸上比划) 代入3个已知点, 问题变为: ( x – x0 )2 + ( y – y0 )2 = r2, ( x1 – x0 )2 + ( y1 – y0 )2 = r2, 求 x0, y0, r ( x2 – x0 )2 + ( y2 – y0 )2 = r2, ( x3 – x0 )2 + ( y3 – y0 )2 = r2,
化简, 问题再变为: (x2-x1)x0+(y2-y1)y0 = ( x22-x12 + y22-y12 ) / 2 , 求出 x0, y0 (x3-x1)x0+(y3-y1)y0 = ( x32-x12 + y32-y12 ) / 2 , , 即2点的距离。 再得 现在问题转化为: 对一个二元一次方程的求解和求2点之间的距离。 a11, a12, a21, a22, b1, b2, 为了使算法更清晰, 引入中间变量: 类型皆为 double, 置值为: a11 = x2 - x1; a12 = y2 - y1; b1 = ( x22- x12 + y22- y12 ) / 2; a21 = x3 - x1; a22 = y3 - y1; b2 = ( x32- x12 + y32- y12 ) / 2; 则问题进一步转化为: a11x0+a12y0 = b1 , 求出 x0, y0 a21x0+a22y0 = b2 , 此时, 可解出: x0 = ( b1 * a22 – a12 * b2 ) / ( a11 * a22 - a12 * a21 ); 草稿打完 y0 = ( a11 * b2 – a21 * b1 ) / ( a11 * a22 - a12 * a21 );
程海无边, 回头是岸; break? 我们continue, 下一步就在机器上敲入程序了。 步1. 先搭框架 #inlcude <stdio.h> #include <math.h> void main() { } 注意: 要齐整! 向前看齐。
步2. 变量先定义好 (在草稿中Baidu一下) #inlcude <stdio.h> #include <math.h> void main() { double x1, y1, x2, y2, x3, y3; // 这是存放输入的 double x0, y0, r; // 这是放结果的 double a11, a12, a21, a22, b1, b2; // 这些是临时存数用的 }
步3. 加数据输入和结果输出代码 #inlcude <stdio.h> #include <math.h> void main() { double x1, y1, x2, y2, x3, y3; double x0, y0, r; double a11, a12, a21, a22, b1, b2; scanf( ”%lf%lf%lf%lf%lf%lf”, &x1, &y1, &x2, &y2, &x3, &y3 ); printf( ”(%lf,%lf), r = %lf”, x0, y0, r ); }
步4. 添加数据加工用的核心代码 (在草稿中Google一下) #inlcude <stdio.h> #include <math.h> void main() { double x1, y1, x2, y2, x3, y3; // 这是存放输入的 double x0, y0, r; // 这是放结果的 double a11, a12, a21, a22, b1, b2; // 这些是临时存数用的 scanf( ”%lf%lf%lf%lf%lf%lf”, &x1, &y1, &x2, &y2, &x3, &y3 ); a11 = x2 - x1; a12 = y2 - y1; a21 = x3 - x1; a22 = y3 - y1; b1 = ( x2*x2 - x1*x1 + y2*y2 - y1*y1 ) / 2; b2 = ( x3*x3 - x1*x1 + y3*y3 - y1*y1 ) / 2; x0 = ( b1 * a22 – a12 * b2 ) / ( a11 * a22 - a12 * a21 ); y0 = ( a11 * b2 – a21 * b1 ) / ( a11 * a22 - a12 * a21 ); r= sqrt( ( x1 - x0 ) * ( x1 - x0 ) + ( y1 – y0 ) * ( y1 – y0 ) ); printf( ”(%lf,%lf), r = %lf”, x0, y0, r ); } 直接从代码上能看出做什么吗?
步5. 运行试试 运行结果 整半天, 就这几行代码? 要这么费劲?
示例19 问题: 求三元一次方程组的解。 1. 输入: a11,a12,a13; a21,a22,a23; a31,a32,a33; b1,b2,b3; 类型皆为 double x1, x2, x3; 2. 输出: 类型皆为 double 3. 算法: a11x1 + a12x2 + a13x3 = b1 a21x1 + a22x2 + a23x3 = b2 由 第3个式子中解出x3代入前2个式子 a31x1 + a32x2 + a33x3 = b3 (a11- a31*a13/a33)x1 + (a12-a32*a13/a33)x2 = b1-b3*a13/a33 得 (a21- a31*a23/a33)x1 + (a22-a32*a23/a33)x2 = b2-b3*a23/a33 (这是一个二元一次方程组, 我们不引入中间变量来存放系数和 右端项, 我们计算后仍将其放在a11,a12,a21,a22,b1,b2变量中) 解出 x1, x2, 并得 x3 = ( b3 - a31x1 - a32 x2 ) / a33;
4. 代码 #inlcude <stdio.h> void main() { double a11, a12, a13, a21, a22, a23, a31, a32, a33, b1, b2, b3; // 这是存放输入的 double x1, x2, x3; // 这是放结果的 scanf( ”%lf%lf%lf%lf”, &a11, &a12, &a13, &b1 ); // 第1行输入 scanf( ”%lf%lf%lf%lf”, &a21, &a22, &a23, &b2 ); // 第2行输入 scanf( ”%lf%lf%lf%lf”, &a31, &a32, &a33, &b3 ); // 第3行输入 // 临时存放 a11=(a11- a31*a13/a33);a12 = (a12-a32*a13/a33);b1 = b1-b3*a13/a33; a21=(a21- a31*a23/a33);a22 = (a22-a32*a23/a33);b2 = b2-b3*a23/a33; x1 = ( b1 * a22 – a12 * b2 ) / ( a11 * a22 - a12 * a21 ); // 这2句参考例18 x2 = ( a11 * b2 – a21 * b1 ) / ( a11 * a22 - a12 * a21 ); x3 = ( b3 - a31 * x1 - a32 * x2 ) / a33; printf( ”x1=%lf, x2=%lf, x3=%lf”, x1, x2, x3 ); } 5. 运行试验
问题: 求经过三点的一条抛物线。 示例20 1. 输入: 三个点( x1, y1), ( x2, y2 ), ( x3, y3 ); 类型皆为 double 2. 输出: a, b, c使 y = ax2 + bx + c 经过以上3点; 类型皆为 double 3. 算法: y = ax2 + bx + c; 代入3个已知点, 问题变为: x12a + x1b + c = y1 x22a + x2b + c = y2 求 a, b, c; x32a + x3b + c = y3, 这样, 可利用上例中的程序代码, 请在代码中核对。
4. 代码 #inlcude <stdio.h> void main() { double x1, y1, x2, y2, x3, y3; // 这是存放输入的 double a, b, c; // 这是放结果的 double a11, a12, a13, a21, a22, a23, a31, a32, a33, b1, b2, b3; // 这是放临时值的 scanf( ”%lf%lf%lf%lf%lf%lf”, &x1, &y1, &x2, &y2, &x3, &y3 ); // 3点输入 // 准备系数和右端项 a11 =x1 * x1; a12 = x1; a13 = 1; b1 = y1; a21 =x2 * x2; a22 = x2; a23 = 1; b2 = y2; a31 =x3 * x3; a32 = x3; a33 = 1; b3 = y3; a11=(a11- a31*a13/a33);a12 = (a12-a32*a13/a33);b1= b1-b3*a13/a33; a21=(a21- a31*a23/a33);a22 = (a22-a32*a23/a33);b2= b2-b3*a23/a33; a = ( b1 * a22 – a12 * b2 ) / ( a11 * a22 - a12 * a21 ); b = ( a11 * b2 – a21 * b1 ) / ( a11 * a22 - a12 * a21 ); c = ( b3 - a31 * a - a32 * b ) / a33; printf( ”y =%lf*x*x+%lf*x+%lf”, a, b, c ); // 结果显示 } 5. 运行试验(自己完成)
本章总结 2. 常量与变量 常量就是固定数, 整型实型要区分; 变量用于存数值, 数值也分整和实。 1. 数值 变量起名要慎重, 字母起头要牢记; 值分二类整和实, 范围精度各不同; 使用之前先定义, 之后才能存和取。 对应int与double, 区别仅在小数点。 整和实, 可转换, 默认强制由你选; 3. 运算 实转整, 丢小数, 小数指数表实数。 常量变量皆是数, 加减乘除取余数; 整数实数存内存, 内部格式大不同; 每步运算有结果, 所得结果有类型。 实数整数皆有用, 事先你得想充分。 运算顺序别忘记, 乘除加减括号先; 整数用于计个数, 数值判断全精确; 机器运算很老实, 相同运算左到右。 实数用于算数值, 超过精度会舍去。 左边变量右边数, 等号也是运算符; 算术运算表达式, 结果赋入变量中。
4. 语句 5. 程序 说明语句定类型, 赋值语句存结果; main作为主函数, 程序入口在起首; 键盘输入scanf(), 屏幕输出printf()。 变量说明前面放, 执行语句后面跟。 输入输出加处理, 编程步骤要牢记; 简单语句带分号, 分隔常常用逗号; 函数还可自定义, 输入输出更清晰。 数学函数比较多, 你想要的它都有。 草稿纸上细细画, 行行语句整整齐; 语句还有一大堆, 变量类型也较多; 条件分支与循环, 地址数组加结构。 程序运行出错误, 逐行调试极方便。