第四章函数--函数初体验项目5拓展1输出三角函数表v1.0

本文介绍了一个不使用数学库函数而自定义sin函数的方法,并通过一个C++程序实现了角度值为min_angle到max_angle之间(间隔为1度)的所有角度的正弦值输出。程序以速查表的形式展示结果,适用于学习自定义数学函数。
上机内容:要求在main()函数中调用show_sin_table(min_angle, max_angle),
  显示角度值为min_angle到max_angle之间的所有角度(间隔为1度)的正弦值。
  要求不能用数学库函数,将项目6中的mysin函数拷贝到这个程序中,用于计算sin值。
  例如show_sin_table(0, 90)可以显示出所有0到90度的正弦值。
  为取得更好的效果,可以考虑像英尺到米的转换一样,以速查表格的形式给出结果。
 注:version1.0 输出0到任意角(100度以内)的正弦函数值
上机目的:利用函数编程,学会自定义sin和cos函数
我的程序:
/*  
* 程序的版权和版本声明部分:  
* Copyright (c) 2013, 青岛农业大学理信学院  
* All rights reserved.  
* 文件名称:输出三角函数表.cpp  
* 作    者:幻影行者  
* 完成日期:2013 年 8 月 4 日  
* 版 本 号:v1.0  
* 对任务及求解方法的描述部分: 
* 输入描述:略  
* 问题描述:要求在main()函数中调用show_sin_table(min_angle, max_angle),
            显示角度值为min_angle到max_angle之间的所有角度(间隔为1度)的正弦值。
			要求不能用数学库函数,自定义mysin函数用于计算sin值。
			例如show_sin_table(0, 90)可以显示出所有0到90度的正弦值。
			为取得更好的效果,可以考虑像英尺到米的转换一样,以速查表格的形式给出结果。 
* 程序输出:输出三角函数表  
* 问题分析:略 
* 算法设计:略  
*/

//version1.0 输出0到任意角(100度以内)的正弦函数值
#include<iostream>
#include<iomanip>
using namespace std;
const double pi=3.141592653;   //常变量
double myabs(double);    //函数声明部分,自定义求绝对值函数,用于判断循环结束条件,设置类型为double,因需要设置精度小于0.00001时结束累加
double mysin(double);    //自定义sin函数
double mycos(double);    //自定义cos函数
double factorial(double); //自定义求阶乘的函数
void show_sin_table(int,int);  //自定义输出三角函数表的函数

int main()
{
	double minAngle,maxAngle;   //角度的最小值和最大值
	cout<<"please enter the minimum angle and the maximum angle: "<<endl;
	cin>>minAngle>>maxAngle;
	cout<<"The table is:"<<endl;
	show_sin_table(minAngle,maxAngle);
	return 0;
}

//自定义输出三角函数表的函数
void show_sin_table(int min_angle,int max_angle)
{
	int i,j,k,m;
	cout<<"sinx"<<'\t';  //第一行输出:先输出表头
	for(m=0;m<=9;++m)     //再输出表头后面的内容
	{
	    cout<<m<<'\t';
	}
	cout<<endl;

	if(min_angle<max_angle)  //自第二行以后的输出
	{
		for(i=0;i<=(max_angle/10);++i)    //角度值由(行号i*10+列号j)确定
		{
			cout<<i<<'\t';
            for(j=0;j<=9;++j)
			{
				double d=i*10+j;  //由行号列号确定角度值
				cout.precision(3);  //设置精度
				if((i==(max_angle/10))&&(j>(max_angle%10))) //只输入所求最大角max_angle以内的角的sin值
				{
                     //什么也不做,确保不再输出大于最大角度max_angle的sin值
				}
				else
				{
					cout<<mysin(d*pi/180)<<"\t";
					if((j+1)==10) //输入10个值后换行
						cout<<endl;
				}
				if(d>max_angle) //若角度大于所输入的最大角度max_angle,则不再输出,且换行
				{
					cout<<endl;
				}
			}
		}
	}
	else
	{

	}

}

//自定义sin函数
double mysin(double x)
{
	int k=1,sign=-1;  // sign用于控制每一项前面的符号,为方便计算,从第二项开始,故sign初值为-1,k=1
	double sum=x,item;     //sum代表函数值,从第二项开始,sum初值为x,item代表每一项的值
	double n=x,d;    // n代表分子(numerator),d代表分母(denominator)
	do
	{
		n*=(x*x);      //每一项的分子中,x的幂都相应地比它前一项多2
		d=factorial(2*k+1);   //调用factorial函数求阶乘,每一项的分母中都是奇数的阶乘
		item=sign*(n/d);   //计算每一项的值,并累加到sum中
		sum+=item;  
		sign=-sign; // 实现加一项减一项
		++k;
		}while(myabs(item)>1e-5);  /*思维误区:易写成myabs(item)<1e-5,正确理解,“当最后一项的绝对值小于0.00001时,累加结束”*/
	                              
	return sum;	
}

//自定义cos函数
double mycos(double x)
{
	int k=1,sign=-1;  
	double sum=1,item;     //相比于mysin函数,这里sum初值为1
	double n=1,d;          //这里n=1
	do
	{
		n*=(x*x);      
		d=factorial(2*k);   //每一项的分母中都是偶数的阶乘
		item=sign*(n/d);   
		sum+=item;  
		sign=-sign; 
		++k;
	}while(myabs(item)>1e-5); 
	return sum;	
}

//自定义求绝对值的函数
double myabs(double a)
{
	//return((a>=0)?a:-a);
	if(a>=0)
		return a;
	else 
		return -a;		
}

//自定义求阶乘的函数
double factorial(double a)
{
	double sum=1;
	for(int i=1;i<=a;++i)
		sum*=i;
	return sum;
}

运行结果:

<think>嗯,用户想用C语言开发一个计算器,支持加减乘除、单字符输入、容错处理,还有高级运算比如开根号和三角函数。首先,我得考虑如何分解这个问题。可能需要分步骤实现,先处理基本功能,再考虑拓展部分。 首先,基本运算的话,可能需要用switch语句来处理不同的操作符,比如+、-、*、/。然后,单字符输入可能涉及到读取用户输入的数字和操作符,这里要注意处理多位数的情况,可能需要一个循环来读取连续的数字字符,直到遇到非数字为止。比如用户输入123+456,程序需要正确解析出123和456这两个操作数。 然后,容错处理是关键。比如除数为零的情况,或者用户输入了无效的字符,这时候程序需要给出错误提示而不是崩溃。这可能需要一些条件判断,比如在除法运算前检查除数是否为零,或者在解析输入时检查是否有非数字字符。 接下来是高级运算,比如开根号和三角函数。这些可能需要用到数学库里的函数,比如sqrt、sin、cos等,所以在编译的时候需要链接数学库,也就是加上-lm参数。另外,用户输入这些高级运算的符号,比如用's'示开根号,'t'三角函数,这时候需要如何解析输入呢?可能需要设计一种方式,比如操作符后面跟着一个字符示具体的高级运算,比如t后面加s示sin,tc示cos等。 然后是达式解析的问题。用户输入的可能是一个连续的达式,比如3+5*2,或者sqrt(9)+sin(30),这时候需要考虑运算优先级和括号处理。不过用户提到的是单字符输入,可能意味着达式是逐个字符输入的,比如先输入3,然后+,然后5,然后*,这样可能需要更复杂的处理,或者用户输入的是类似命令行计算器,每次输入一个完整的达式。这里可能需要进一步明确,但根据问题描述,可能更倾向于逐个字符处理,比如用户输入一个数字,再输入一个操作符,再输入另一个数字,进行计算。不过对于高级运算,可能操作符后面需要一个参数,比如sqrt(25),这时候需要处理函数式的输入。 或者,用户希望的是输入像传统的命令行计算器,一次输入整个达式,比如“3 + 4 * 2”,然后程序解析并计算。这时候需要更复杂的达式解析,可能涉及逆波兰式或者栈的使用。不过根据用户提到的“单字符输入”,可能更倾向于逐个字符处理,比如每次输入一个操作符和一个数字,但这样可能不太现实。可能需要进一步明确,但根据问题描述,可能用户希望的是支持单字符的操作符,比如输入'+'代加法,'s'代平方根等。 另外,关于达式解析,可能需要使用栈来处理运算优先级,或者采用递归下降的方法。不过对于初学者来说,可能更简单的方式是按顺序处理,不考虑优先级,或者要求用户使用括号明确优先级。不过用户的需求里没有特别提到运算优先级,可能暂时不考虑,先实现基本功能,再逐步扩展。 对于错误处理,除了除零错误,还需要处理无效的操作符,比如用户输入了未定义的符号,这时候程序应该提示错误并可能要求重新输入。同时,输入的数字可能包含非数字字符,比如12a3,这时候需要检测并报错。 关于代码结构,可能需要一个主循环,不断读取用户的输入,直到用户选择退出。每次循环中,读取数字和操作符,进行计算,并输出结果。对于高级运算,可能需要不同的处理分支,比如判断操作符是's'则调用sqrt函数,同时需要读取一个操作数。 测试方面,可能需要逐步测试每个功能,先测试加减乘除,确保基本运算正确,然后加入错误处理,测试各种错误情况,比如除零、无效字符等,最后加入高级运算,确保函数调用正确,并且处理了负数开根号等错误情况。 另外,关于三角函数的输入,可能需要用户输入角度还是弧度?通常数学库的函数使用弧度,但用户可能更习惯输入角度,所以可能需要转换,比如将输入的角度乘以π/180转换为弧度后再计算sin或cos。 总结一下,步骤可能是: 1. 实现基本加减乘除,支持单字符操作符。 2. 处理多位数输入,正确解析操作数。 3. 添加错误处理:除零、无效操作符、无效数字。 4. 实现高级运算:sqrt、sin、cos,可能需要扩展操作符解析。 5. 处理高级运算的错误,比如sqrt的负数输入。 6. 整合所有功能,进行测试。 在代码实现上,可能需要使用双精度浮点数来支持小数和更精确的计算。读取输入时,可能需要逐个字符读取,使用缓冲区存储数字,直到遇到非数字字符,然后将缓冲区转换为数字。例如,用户输入123+45,程序读取'1','2','3',然后遇到'+',将"123"转换为数字,接着读取操作符'+',然后读取'4','5'转换为45,进行计算。 对于高级运算,比如sqrt,可能需要用户输入's'后跟数字,或者设计成类似命令的方式,比如用户输入's 25'来计算平方根。或者,可能需要修改操作符的处理方式,支持多字符操作符,比如用'sqrt'作为操作符,但这样会增加解析的复杂性。根据用户提到的“单字符输入”,可能操作符是单个字符,比如's'代sqrt,'t'代三角函数,后面可能需要另一个字符来区分sin、cos等,比如't'后跟's'示sin,'c'示cos,这样操作符可能是两个字符的组合。 总之,需要明确操作符的设计,确保用户输入的方式符合预期,同时代码能够正确解析。这可能需要一些条件判断,比如检查操作符的第一个字符是否为's',如果是,则执行sqrt操作,或者检查前两个字符是否为't'和's'来执行sin函数。 最后,代码的结构需要清晰,函数模块化,比如将输入解析、计算、错误处理分成不同的函数,提高可读性和可维护性。</think>### C语言计算器实现步骤分解 #### 一、基础框架搭建 ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #define MAX_INPUT 100 double memory = 0; // 存储器功能拓展 ``` #### 二、输入处理模块 ```c void process_expression(char* expr) { double num1 = 0, num2 = 0; char op; int pos = 0; // 解析第一个操作数 while (isdigit(expr[pos]) || expr[pos] == '.') { num1 = num1 * 10 + (expr[pos] - '0'); pos++; } // 获取运算符 op = expr[pos++]; // 处理高级运算 if (op == 's' || op == 'c' || op == 't') { // 三角函数和开根号处理 if (op == 's' && expr[pos] == 'q') { pos += 2; // 跳过'qrt' num1 = sqrt(num1); } else if (op == 's') { num1 = sin(num1 * M_PI / 180); // 角度转弧度 } printf("= %.2f\n", num1); return; } // 解析第二个操作数 while (isdigit(expr[pos]) || expr[pos] == '.') { num2 = num2 * 10 + (expr[pos] - '0'); pos++; } ``` #### 三、运算核心模块 ```c switch(op) { case '+': printf("= %.2f\n", num1 + num2); break; case '-': printf("= %.2f\n", num1 - num2); break; case '*': printf("= %.2f\n", num1 * num2); break; case '/': if (num2 == 0) { printf("错误:除数不能为零\n"); return; } printf("= %.2f\n", num1 / num2); break; default: printf("错误:无效运算符\n"); } } ``` #### 四、主程序结构 ```c int main() { char input[MAX_INPUT]; printf("科学计算器 v1.0\n"); printf("支持运算符: + - * / sqrt() sin cos\n"); printf("输入示例: 3+5 或 sqrt(25) 或 sin(30)\n"); while(1) { printf("> "); fgets(input, MAX_INPUT, stdin); // 输入验证 if (!validate_input(input)) { printf("错误:非法输入格式\n"); continue; } process_expression(input); } return 0; } ``` #### 五、关键增强功能实现 1. **输入验证函数**: ```c int validate_input(const char* input) { int has_operator = 0; for (int i = 0; input[i] != '\n' && input[i] != '\0'; i++) { if (!isdigit(input[i]) && input[i] != '.' && input[i] != '+' && input[i] != '-' && input[i] != '*' && input[i] != '/' && input[i] != 's' && input[i] != 'c' && input[i] != 't' && input[i] != '(' && input[i] != ')') { return 0; } } return 1; } ``` 2. **存储器功能拓展**: ```c void memory_operations(char op, double value) { switch(op) { case 'M': memory = value; break; case 'A': memory += value; break; case 'S': memory -= value; break; case 'R': printf("存储器值: %.2f\n", memory); break; } } ``` #### 六、编译运行指令 ```bash gcc calculator.c -o calculator -lm ./calculator ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值