C语言高精度计算器pro版(实现简单/功能多/彩色界面/文件读写)

1.问题描述

使用C语言实现高精度计算器,实现相应的高精度算法来完成基本运算,能处理大整数和高精度小数。

2.问题分析

我们知道,计算机内部直接使用int或者double等数据类型存储数据是有范围限制的,当运算数据较大时,计算机将会出现溢出情况,使得计算结果不够精确。例如,一个20位的十进制整数,如果用int类型变量存放,就会出现数据溢出。当运算数超出了整型、实型能表示的范围,肯定不能直接用一个数的形式来表示。在运算过程中,能表示大数的数据类型有两种:整型数组和字符串。

整型数组:每个元素存储1位,有多少位就需要多少个数组元素;每一位都是数的形式,可直接加减,运算时非常方便,但整型数组不能直接输入全部元素,只能一个一个输入,并且输入时,每两位数之间必须有分隔符,不符合人们输入数值的习惯,输入输出时不方便。

字符串(本质上是一个字符数组):字符串的最大长度是多少,就可以表示多少位数字。用字符串表示数值能将全部位直接输入输出,但字符串中的每一个位是一个字符,必须将它转换为数值再进行运算,运算时不方便。

综合整型数组和字符数组的优缺点来看,我们在接下来的问题中,用字符串读入数据,运算时转存到整型数组中进行运算。事实上,高精度运算就是通过编程的方法,把简单数学的运算步骤在计算机上完美地演示一遍。

3.模块划分

高精度计算器划分为以下几个模块:

辅助函数部分:

颜色控制函数

void color(short x) //自定义函根据参数改变颜色

异常退出函数

void iexit()//iexit非法字符退出函数

运算部分:

科学计算器模块(用于科学计数法的运算)

void easy()

高精度加法模块

void add()

高精度减法模块

void minus()

高精度乘法模块

void multi()

高精度除法模块

int setZero(short int*num,int len)//将数组清0的函数

int compare(short int*num1,short int*num2){//数组太大且比较多次,需要专门用一个函数比较两个数组形式数字大小

int copy(short int*num1,short int*num2)//传入数组指针

void divi(){//高精度除法主函数

高精度阶乘模块

void fact()

高精度小数模块

void floats()

高精度斐波那契模块

typedef struct BigInts//typedef创建结构体变量

void init(BigInt* a, int x)  // 将a初始化为x

void print(BigInt* a,int n)  // 输出BigInt表示的整数

BigInt added(BigInt a, BigInt b)  //小型高精度加法程序

void fib(int n)  //用于计算n个斐波那契数列数

void fibmain()//高精度斐波那契主函数

帮助部分:

帮助输出模块

void help()

选择部分:

功能选择模块(用于选择功能,实现循环调用功能和退出)

int main()

4.流程设计

5.用户使用说明

高精度计算器使用说明

一、本高精度计算器的功能

1.科学计算器2.高精度加法3.高精度减法4.高精度乘法5.高精度除法6.高精度阶乘7.高精度小数8.高精度斐波那契

二、本计算器的使用流程

1.在菜单页面选择一个功能选项或直接退出

2.功能启动,输入进行运算的数。

3.运算完毕,输出结果

4.选择下一个功能选项或退出

三、本计算器各功能的使用方法

1.科学计算器

本功能以科学计数法的形式输出。

进入功能后选择运算列表:1.加 2.减 3.乘 4.除,回车确认。

输入第一个数,回车确认。

输入第二个数,回车确认。

即得到答案,按任意键返回菜单。

2.高精度加法

本功能支持100000位以内的正整数相加!

若要从txt文件输入请将存有两个数的num.txt放入此文件夹(注意:两个数字换行隔开)。

输入是否从txt读入(0.否,1.是),回车确认。(非1均默认为否)

不从txt读入则输入第一个数,回车确认。输入第二个数,回车确认。

得到答案,选择是否将答案保存为txt(0.否,1.是)。(非1均默认为否)

选择是则答案保存至文件夹内ans.txt,按任意键返回菜单。

3.高精度减法

本功能支持100000位以内的正整数相减!用法与高精度加法相同。

4.高精度乘法

本功能支持1000位以内的正整数相乘!用法与高精度加法相同。

5.高精度除法

本功能支持10000位以内的正整数相除!答案由商和余数构成,需要小数请移步高精度小数!用法与高精度加法相同。

6.高精度阶乘

本功能支持25000以内的正整数阶乘!

输入正整数,回车确认。

得到答案,选择是否将答案保存为txt(0.否,1.是)。(非1均默认为否)

选择是则答案保存至文件夹内ans.txt,按任意键返回菜单。

7.高精度小数

本功能支持分子和分母在24位以内的分数,包括真分数和假分数!

输入分子/分母,回车确认。

得到答案,按任意键返回菜单

8.高精度斐波那契

本功能支持输出斐波那契数列前30000项!

输入要计算的斐波那契数列的项数,回车确认。

得到答案,选择是否将答案保存为txt(0.否,1.是)。(非1均默认为否)

选择是则答案保存至文件夹内ans.txt,按任意键返回菜单。

9.帮助

显示使用说明

0.退出

退出程序

6.代码实现


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
//版本定义区
#define version "4.0"
//精度宏定义区
#define addMAX 100001//高精度加法精度
#define minusMAX 100000//高精度减法精度
#define multiMAX 1000//高精度乘法精度
#define diviMAX 10000//高精度除法精度
#define MAX_N 30000 //定义斐波那契数列序列最大值
//颜色宏定义区
#define run color(10)//功能标签颜色
#define choose SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),9|0|8|0)//选择型标签颜色
#define re color(7)//恢复颜色
#define tip SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11|0|8|0)//温馨提示颜色



void color(short x)	//自定义函根据参数改变颜色 
{
    if(x>=0 && x<=15)//参数在0-15的范围颜色
    	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);	//只有一个参数,改变字体颜色 
    else//默认的颜色白色
    	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
/*
颜色函数SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),前景色 | 背景色 | 前景加强 | 背景加强);
	前景色:数字0-15 或 FOREGROUND_XXX 表示	(其中XXX可用BLUE、RED、GREEN表示) 
	前景加强:数字8 或 FOREGROUND_INTENSITY 表示
	背景色:数字16 32 64 或 BACKGROUND_XXX 三种颜色表示 
	背景加强: 数字128 或 BACKGROUND_INTENSITY 表示
前景颜色对应值: 
  0=黑色                8=灰色  
   1=蓝色                9=淡蓝色                                         
  2=绿色                10=淡绿色                 
  3=湖蓝色              11=淡浅蓝色      
  4=红色                12=淡红色         
  5=紫色                13=淡紫色               
  6=黄色                14=淡黄色                
  7=白色                15=亮白色      
*/

//iexit非法字符退出函数
void iexit(){
    re;
    color(12);
    printf("输入存在非法字符!");
    color(8);
    printf("\n即将自动返回菜单!\n");
    color(16);
    system("PAUSE");
}


//1.>----------------------科学计算器----------------------<
void easy(){
    int select;// 选择的简单计算器功能
    double a, b;// 定义算术的两个数
    int c;
    color(14);printf(">------------------------科学计算器启动------------------------<\n");
    tip;printf("温馨提示:本功能以科学计数法的形式输出!\n");re;
    color(14);printf("运算列表:1.加 2.减 3.乘 4.除\n");
    choose;printf("请选择功能:");re;
            scanf("%d", &select);
            while (select < 1 || select > 4) {// 只允许选择菜单栏内的数字,体现安全性
            color(12);printf("请输入合理的选项!\n");re;
            choose;printf("请请重新选择菜单功能:");re;
            scanf("%d",&select);
        }
    run;printf("请输入第一个数:");re;
    c=scanf("%lf",&a,&b);
    run;printf("请输入第二个数:");re;
    c=scanf("%lf",&b);
    run;printf("答案为:");color(15);
    switch (select) {
            case 1:
                printf("%e",a+b);
                break;
            case 2:
                printf("%e",a-b);
                break;
            case 3:
                printf("%e", a*b);
                break;
            case 4:
                if (b==0)
                {
                color(4);printf("0不能做除数!");
                }
                else printf("%e",a/b);
                break;
    }
    color(8);printf("\n运算完毕!即将自动返回菜单!\n");re;
    system("PAUSE");
    return;
}

//2.>----------------------高精度加法----------------------<
void add(){
    color(14);printf(">------------------------高精度加法启动------------------------<\n");
    tip;printf("温馨提示:本功能支持%d位以内的正整数相加!\n",addMAX-1);
    printf("若要从txt文件输入请将存有两个数的num.txt放入此文件夹(两个数字换行隔开)\n");
    char s[addMAX],ss[addMAX];
    short int a[addMAX],b[addMAX];
    int len;
    int txt=0;
    char ch;
    run;printf("是否从txt读入(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    { FILE* fp; 
        if ((fp = fopen("num.txt", "r")) == NULL)
        {
            color(12);printf("读取 num.txt 失败");
            color(8);printf("\n即将自动返回菜单!\n");color(16);
            system("PAUSE");
            return;
        }
        else{
            int i=0;
            
        while(1){//循环读取
            fread(&ch, sizeof(char), 1, fp);
            if (ch==10)//分隔标记
            {
                break;
            }
            s[i]=ch;
            i++;
            }
        fgets(ss, addMAX, fp);
        }
        run;printf("第一个正整数:");re;
        printf("%s\n",s);
		run;printf("第二个正整数:");re;
        printf("%s\n",ss);
        fclose(fp);
	}
    else{
    run;printf("请输入第一个正整数:");re;//字符串形式输入
    scanf("%s",s);
    run;printf("请输入第二个正整数:");re;
    scanf("%s",ss);}
    int l1 = strlen(s);
	int l2 = strlen(ss); 
	if (l1 > l2) 
		len = l1;      
	else 
		len = l2;//len赋值为其中大的数
	memset(a,0,sizeof(a));    //清零
	memset(b,0,sizeof(b));    
	for (int i = l1 - 1 ; i >= 0 ; i--)    //倒过来输入数组
		{
            a[l1 - i - 1] = s[i] - '0';
        if (a[l1-i-1]<0 || a[l1-i-1]>9)
        {
            iexit();return;}//iexit非法字符退出函数
        }        
	for (int i = l2 - 1 ; i >= 0 ; i--)    
		{b[l2 - i - 1] = ss[i] - '0';
        if (0>b[l2-i-1]||b[l2-i-1]>9){
            iexit();return;
            }//iexit非法字符退出函数
        }      

	for (int i = 0 ; i < len ; i++)//进位
	{
		a[i] = a[i] + b[i];    
		a[i+1]+= a[i] / 10;    
		a[i] = a[i] % 10;      
	}
	if (a[len] != 0) len++;    //长度是否增加

	while (a[len - 1] == 0 && len>1)
        len--;	//while去零
	run;printf("答案为:");color(15);
	for (int i = len - 1 ;i >= 0 ;i--)
		printf("%d",a[i]); 
	color(16);printf("\n(tip:此答案共%d位)\n",len);
    
    run;printf("是否将答案保存为txt(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    {FILE* fp; 
        fp = fopen("ans.txt", "w");  
    if (!fp) {  
        perror("保存为txt失败");  
    }  
    else {
        for (int i = len - 1 ;i >= 0 ;i--)
        fputc(a[i]+48,fp);
        run;printf("答案已保存至ans.txt!");re;
        }
        fclose(fp);
    }
    
    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    return;
}

//3.>----------------------高精度减法----------------------<
void minus()
{   char s[minusMAX],ss[minusMAX];
    short int a[minusMAX],b[minusMAX];//short int节约内存
    color(14);printf(">------------------------高精度减法启动------------------------<\n");
    tip;printf("温馨提示:本功能支持%d位以内的正整数相减!\n",minusMAX);
    printf("若要从txt文件输入请将存有两个数的num.txt放入此文件夹(两个数字换行隔开)\n",addMAX-1);
    int txt=0;
    char ch;
    run;printf("是否从txt读入(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    { FILE* fp; 
        if ((fp = fopen("num.txt", "r")) == NULL)
        {
            color(12);printf("读取 num.txt 失败");
            color(8);printf("\n即将自动返回菜单!\n");color(16);
            system("PAUSE");
            return;
        }
        else{
            int i=0;
            
        while(1){//循环读取
            fread(&ch, sizeof(char), 1, fp);
            if (ch==10)//分隔标记
            {
                break;
            }
            s[i]=ch;
            i++;
            }
        fgets(ss, addMAX, fp);
        }
        run;printf("第一个正整数:");re;
        printf("%s\n",s);
		run;printf("第二个正整数:");re;
        printf("%s\n",ss);
        fclose(fp);
	}
    else{
    run;printf("请输入第一个正整数:");re;//字符串形式输入
    scanf("%s",s);
    run;printf("请输入第二个正整数:");re;
    scanf("%s",ss);}
    int l1 = strlen(s);    //字符串长度 
    int l2 = strlen(ss);
    int len; 
    int flag = 0;         //一个记录正负的变量
    memset(a,0,sizeof(a));       
    memset(b,0,sizeof(b));  

    if ( l1 < l2 || (strcmp(s,ss) < 0 && l1 == l2) )    //判断前后两数的大小的  
    {                                           
        flag = 1; //把正负记录下来  
        for (int i = l2 - 1 ; i >= 0 ; i--)    //倒过来输入 
            {a[l2 - i - 1] = ss[i] - '0';//将字符串里的字符转换为数字
            if (0>a[l2-i-1]||a[l2-i-1]>9){
                iexit();return;
                }//iexit非法字符退出函数 
            }      
        for (int i = l1 - 1 ; i >= 0 ; i--)
            {b[l1 - i - 1] = s[i] - '0';
            if (0>b[l1-i-1]||b[l1-i-1]>9){
                iexit();return;
                }//iexit非法字符退出函数
            }
    }
    else
    {
        for (int i = l1 - 1 ; i >= 0 ; i--)   
            {a[l1 - i - 1] = s[i] - '0';
            if (0>a[l1-i-1]||a[l1-i-1]>9){
                iexit();return;
                }//iexit非法字符退出函数
            }
        for (int i = l2 - 1 ; i >= 0 ; i--)
            {b[l2 - i - 1] = ss[i] - '0';
            if (0>b[l2 - i - 1]||b[l2 - i - 1]>9){
                iexit();return;
                }//iexit非法字符退出函数
            }
    }
    if (l1 > l2) 
        len = l1;             //len赋值为其中大的数 
    else 
        len = l2; 
    for (int i = 0 ; i < len ; i++)
    {
        a[i] = a[i] - b[i];     //运算 
        if (a[i] < 0)          //如果减得多了 
        {
            a[i+1]-=1;         //向前要一位 
            a[i]+=10;          
        }
    }

    while (a[len - 1] == 0 && len>1) len--;   //while去零
    run;printf("答案为:");color(15);
    if (flag == 1) printf("-");     //如果结果是负的,先输出一个负号 
    for (int i = len - 1 ;i >= 0 ;i--)   //再输出结果 
        printf("%d",a[i]);
    color(16);printf("\n(tip:此答案共%d位)\n",len);

    run;printf("是否将答案保存为txt(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    {FILE* fp; 
        fp = fopen("ans.txt", "w");  
    if (!fp) {  
        perror("保存为txt失败");  
    }  
    else{
        for (int i = len - 1 ;i >= 0 ;i--)
        fputc(a[i]+48,fp);
        run;printf("答案已保存至ans.txt!");re;
        }
    fclose(fp);  
        
    }

    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    return;
}

//4.>----------------------高精度乘法----------------------<
void multi()
{   char num1[multiMAX];
    char num2[multiMAX];
    color(14);printf(">------------------------高精度乘法启动------------------------<\n");
    tip;printf("温馨提示:本功能支持%d位以内的正整数相乘!\n",multiMAX);
    printf("若要从txt文件输入请将存有两个数的num.txt放入此文件夹(两个数字换行隔开)\n",addMAX-1);
    int txt=0;
    char ch;
    run;printf("是否从txt读入(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    { FILE* fp; 
        if ((fp = fopen("num.txt", "r")) == NULL)
        {
            color(12);printf("读取 num.txt 失败");
            color(8);printf("\n即将自动返回菜单!\n");color(16);
            system("PAUSE");
            return;
        }
        else{
            int i=0;
             while(1){//循环读取
            fread(&ch, sizeof(char), 1, fp);
            if (ch!=10)//分隔标记
            {
                num1[i]=ch;
                i++;
            }
            else break;
            }
            num1[i]='\0';
        fgets(num2, multiMAX, fp);
        }
        run;printf("第一个正整数:");re;
        printf("%s\n",num1);
		run;printf("第二个正整数:");re;
        printf("%s\n",num2);
        fclose(fp);
	}
    else{
    run;printf("请输入第一个正整数:");re;//字符串形式输入
    scanf("%s",num1);
    run;printf("请输入第二个正整数:");re;
    scanf("%s",num2);}
    int la,lb,lc;
    short int a[multiMAX]={0},b[multiMAX]={0},c[2*multiMAX]={0};//short int节约内存
    la=strlen(num1);
    lb=strlen(num2);
    for(int i=0;i<la;i++)
    {
        a[la-i-1]=num1[i]-'0';//逆序存放
        if (0>a[la-i-1]||a[la-i-1]>9){
            iexit();return;
            }//iexit非法字符退出函数
    }
    for(int i=0;i<lb;i++)
    {
        b[lb-i-1]=num2[i]-'0';
        if (0>b[lb-i-1]||b[lb-i-1]>9){
            iexit();return;
            }//iexit非法字符退出函数
    }
    lc=la+lb;//记录两个字符串的总长度

    for(int i=0;i<la;i++)
    {
        for(int j=0;j<lb;j++)
        {
            c[i+j]+=a[i]*b[j];
            c[i+j+1]+=c[i+j]/10;
            c[i+j]%=10;
        }
    }
    while(c[lc]==0&&lc>0)lc--;
    char *ret=(char *)malloc(sizeof(char)*(lc+2));//malloc创建动态数组并用指针re指向
    for(int i=lc;i>=0;i--){
        ret[lc-i]=c[i]+'0';
    }
    ret[lc+1]=0;
    run;printf("答案为:");color(15);
    printf("%s",ret);
    color(16);printf("\n(tip:此答案共%d位)\n",lc);

    run;printf("是否将答案保存为txt(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    {FILE* fp; 
        fp = fopen("ans.txt", "w");  
    if (!fp) {  
        perror("保存为txt失败");  
    }  
    else{
        fputs(ret,fp);
        run;printf("答案已保存至ans.txt!");re;
        } 
        fclose(fp);
    }

    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    free(ret);//释放动态数组
}

//5.>----------------------高精度除法----------------------<
/* 用被除数减除数,直到减到其小于除数,减了几次,商就是多少,如果除数和被除数相差较大,那么相减就要花费太多的时间;
本程序采用优化方案:将除数扩大到恰好比被除数小,大大节约了时间。比如;9131和23,将23扩大到2300,再进行减法直到小于除数,减几次就乘以一百,然后在减去减数乘以十,也就是减去230,依此类推;*/
int setZero(short int*num,int len){//将数组清0的函数
	for(int i=0;i<len;i++)
		num[i]=0;
}
int compare(short int*num1,short int*num2){//数字太大且使用多次,需要专门用一个函数比较两个数组形式数字大小
	int i,j;                                //传入数组指针,进行比较
	for(i=diviMAX-1;num1[i]==0;i--);
	for(j=diviMAX-1;num2[j]==0;j--);
	if(i<j)return -1;
	else if(i>j)return 1;
	else{
		for(;i>=0;i--){
			if(num1[i]>num2[i])
				return 1;//大返回1
			else if(num1[i]<num2[i])
				return -1;//小返回-1
		}
		return 0;//相等返回0
	}
}
int copy(short int*num1,short int*num2){//传入数组指针
	int i,j;
	for(i=0;i<diviMAX-1;i++)
		num1[i]=0;
	for(i=diviMAX-1;num2[i]==0;i--);//i成为长度
	for(j=0;j<=i;j++)
		num1[j]=num2[j];//赋值
	return i+1;
}
void divi(){//高精度除法主函数
    char str1[diviMAX];
	char str2[diviMAX];
	color(14);printf(">------------------------高精度除法启动------------------------<\n");
    tip;printf("温馨提示:本功能支持%d位以内的正整数相除!答案由商和余数构成,需要小数请移步高精度小数!\n",diviMAX);
    printf("若要从txt文件输入请将存有两个数的num.txt放入此文件夹(两个数字换行隔开)\n",addMAX-1);
    int txt=0;
    char ch;
    run;printf("是否从txt读入(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    { FILE* fp; 
        if ((fp = fopen("num.txt", "r")) == NULL)
        {
            color(12);printf("读取 num.txt 失败");
            color(8);printf("\n即将自动返回菜单!\n");color(16);
            system("PAUSE");
            return;
        }
        else{
            int i=0;
            
        while(1){//循环读取
            fread(&ch, sizeof(char), 1, fp);
            if (ch==10)//分隔标记
            {
                break;
            }
            str1[i]=ch;
            i++;
            }
            str1[i]='\0';
        fgets(str2, addMAX, fp);
        }
        run;printf("第一个正整数:");re;
        printf("%s\n",str1);
		run;printf("第二个正整数:");re;
        printf("%s\n",str2);
        fclose(fp);
	}
    else{
    run;printf("请输入第一个正整数:");re;//字符串形式输入
    scanf("%s",str1);
    run;printf("请输入第二个正整数:");re;
    scanf("%s",str2);}
    short int a[diviMAX],b[diviMAX],c[diviMAX];//short int节约内存
	setZero(a,diviMAX);
	setZero(b,diviMAX);
	setZero(c,diviMAX);
	
	int i,j,tmp,tmp2=0,borrow=0;//用于记录扩大倍数
    short int temp[diviMAX]={0},temp2[diviMAX]={0};//short int节约内存,存储已减去数字
	int len1=strlen(str1),len2=strlen(str2);
	for(i=0;i<len1;i++)
		{a[i]=str1[len1-1-i]-'0';//存入数组;
        if (0>a[i]||a[i]>9){
            iexit();return;
            }//iexit非法字符退出函数 
            }  
	for(i=0;i<len2;i++)
		{b[i]=str2[len2-1-i]-'0';
         if (0>b[i]||b[i]>9){
             iexit();return;
             }//iexit非法字符退出函数 
            } 
	
	if(compare(a,b)<0){//判断被除数与除数大小
	run;printf("答案为:");color(15);
    printf("0");
    color(16);printf("\n(tip:此答案共1位)");
    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    return;
	}
	while(compare(a,b)>=0){		        //除完一位循环再除下一位                  	
		tmp=len1-len2;
		if(tmp==tmp2&&tmp>0)
			tmp--;
		tmp2=tmp;//扩大倍数
		
		setZero(temp2,diviMAX);
		for(i=len1-1;i>=tmp;i--)
			temp2[i]=b[i-tmp]; 
		copy(temp,a);
		
		if(compare(temp,temp2)<0)
				continue;
		for(j=1;j++;){
			borrow=0;//借位先定义为零
			for(i=tmp;i<len1;i++){
				temp[i]=a[i]-temp2[i]-borrow;//每一位相减
				if(temp[i]<0){
					borrow=1;
					temp[i]+=10;//不够减借1位后的结果
				}
				else
					borrow=0;//够减
			}
			len1=copy(a,temp);//减完一次,temp(余数)赋给a
			    c[tmp]=j;//商
			if(compare(temp,temp2)<0)//减至,temp(余数)小于减数
				break;
		}
	}
	for(i=diviMAX-1;c[i]==0;i--);//除去高位的零
    for(j=diviMAX-1;a[j]==0;j--);//除去高位的零
    len1=i;//答案长度
    len2=j;//余数长度
    run;printf("商为:");color(15);
	for(;i>=0;i--)
		printf("%d",c[i]);
    run;printf("\n余数为:");color(15);
    for(;j>=0;j--)
		printf("%d",a[j]);
    color(16);printf("\n(tip:此答案共%d位,余数共%d位)\n",len1+1,len2+1);

    run;printf("是否将答案保存为txt(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    {FILE* fp; 
        fp = fopen("ans.txt", "w");  
    if (!fp) {  
        perror("保存为txt失败");  
    }
    else{  
        i=len1;//答案长度
        j=len2;//余数长度
        fputs("商为:",fp);
        for(;i>=0;i--)
            fputc(c[i]+48,fp);
            fputc(10,fp);
        fputs("余数为:",fp);
        for(;j>=0;j--)
            fputc(a[j]+48,fp);
        run;printf("答案已保存至ans.txt!");re;
        }
    fclose(fp);
    }

    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    return;
}

//6.>----------------------高精度阶乘----------------------<
void fact(){
    short a[99999] = { 1 };
    int i, up, c, s,n,j;
    
    color(14);printf(">----------------------高精度阶乘启动----------------------<\n");
    tip;printf("温馨提示:本功能支持25000以内的正整数阶乘!\n");
    run;printf("请输入正整数:");
    re;scanf("%d", &n);
    while(n>25000||n<0)
    {
        color(12);printf("请输入不大于25000的正整数!\n请重新输入:");re;
        scanf("%d", &n);
    }
    
    c = 1;
    for (i = 1; i <= n; i++)
    {
    up = 0;//进位
    for (j = 0; j < c; j++)//各位乘i
    {
    s = a[j] * i + up;
    a[j] = s % 10;
    up = s / 10;
    }
    while (up)//位数加
    {
    a[c++] = up % 10;
    up /= 10;
    }
    }
    run;printf("答案为:");color(15);
    for (i = c - 1; i >=0 ;i--)
    {
    printf("%d", a[i]);
    
    }
    color(16);printf("\n(tip:%d的阶乘共%d位)\n",n,c);

    int txt;
    run;printf("是否将答案保存为txt(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    {FILE* fp; 
        fp = fopen("ans.txt", "w");  
    if (!fp) {  
        perror("保存为txt失败");  
    }  
    else{
        for (i = c - 1; i >=0 ;i--)
        {
            fputc(a[i]+48,fp);
        }
        run;printf("答案已保存至ans.txt!");re;
    }
    fclose(fp);  
    }

    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    return;
}

//7.>----------------------高精度小数----------------------<
/* 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现方法。
(0,1)之间的任何浮点数都可以表达为两个正整数的商,为了表达这样两个数的商,可以将相除的结果以多个整数来表示,每个整数表示结果的一位。即商的第一位用一个整数来表示,第二位用另一个整数来表示,以此类推,就可以输出一个高精度的除法结果了。
如16/19的结果0.8421052631…就可以依次输出8、4、2、1、0、5、2、6、3、1…。
而除法的过程,则可以模仿人工列竖式做除法的方式,先将被除数乘以10,得到一位商以后,将余数乘以10作为下一轮计算的被除数 */
void floats()
{
	long long a, b;
	color(14);printf(">----------------------高精度小数启动----------------------<\n");
    tip;printf("温馨提示:本功能支持分子和分母在24位以内的分数!\n");
    run;printf("请输入分子/分母(用“/”隔开):");re;
    scanf("%lld/%lld",&a, &b);
    while(a>LLONG_MAX||b>LLONG_MAX)
    {
        color(12);printf("分子或分母过大!\n请重新输入:");re;
        scanf("%lld/%lld",&a, &b);
    }
	while(b==0)
    {
        color(12);printf("分母为0!\n请重新输入:");re;
        scanf("%lld/%lld",&a, &b);
    }
	int n;
    run;printf("请输入希望得到的小数位数:");re;
    scanf("%d",&n);

    while(n>INT_MAX||n<1)
    {
        color(12);printf("位数过大或小于1!\n请重新输入:");re;
        scanf("%d",&n);
    }
    run;printf("答案为:");color(15);

    if (b>a)
        printf("0.");//真分数输出整数部分0
    if (a>=b)//假分数输出整数部分
    {   
        long long c=a/b;
        printf("%lld.", a/b);
        a %= b;
        
    }
    
	for(int i=1; i<=n; i++)
	{
		a *= 10;
		printf("%d", a/b);//被除数乘以10,得到一位商以后,将余数乘以10作为下一轮计算的被除数
		//if(a%b==0) printf("0");
		a %= b;
	}
    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    
	return ;
}


//8.>----------------------高精度斐波那契----------------------<
typedef struct BigInts{//typedef创建结构体变量
    int len; // 数组长度
    int num[MAX_N]; // 存储每一位的数字
} BigInt;

void init(BigInt* a, int x) { // 将a初始化为x 
    memset(a, 0, sizeof(BigInt));
    a->num[0] = x;
    a->len = 1;
}

void print(BigInt* a,int n) { // 输出BigInt表示的整数
    for (int i = a->len - 1; i >= 0; i--)
        printf("%d", a->num[i]);
    color(16);printf("\n(tip:斐波那契数列第%d项共%d位)\n",n,a->len);

int txt;
    run;printf("是否将答案保存为txt(0.否,1.是):");re;
    scanf("%d",&txt);
    if (txt==1)
    {FILE* fp; 
        fp = fopen("ans.txt", "w");  
    if (!fp) {  
        perror("保存为txt失败");  
    }  
    else{
        for (int i = a->len - 1; i >= 0; i--)
        fputc( a->num[i]+48,fp);
        run;printf("答案已保存至ans.txt!");re;
    }
    fclose(fp);  
    }
}

BigInt added(BigInt a, BigInt b) { //小型高精度加法程序
    BigInt ans;
    memset(&ans, 0, sizeof(ans));

    int carry = 0;
    for (int i = 0; i < a.len || i < b.len || carry; i++) {
        int sum = carry;//上一次的进位
        if (i < a.len) sum += a.num[i];
        if (i < b.len) sum += b.num[i];
        ans.num[i] = sum % 10;
        carry = sum / 10;//本次进位
        ans.len++;
    }

    return ans;
}

void fib(int n) { //用于计算n个斐波那契数列数
    if (n < 1) {
        color(12);
        printf("输入无效!项数必须大于等于1。\n");
        re;
        return;
    }

    if (n>30000) {
        color(12);
        printf("超出范围!输入须小于等于30000。\n");
        re;
        return;
    };
    BigInt a, b, c;
    init(&a, 1); // 初始化a=1
    init(&b, 1); // 初始化b=1
    run;printf("答案为:");color(15);

    if (n == 1) {
        print(&a,n); // 输出第1个斐波那契数列数
        return;
    }

    if (n == 2) {
        print(&b,n); // 输出第2个斐波那契数列数
        return;
    }

    for (int i = 3; i <= n; i++) {
        c = added(a, b); // 计算c=a+b
        a = b; // 更新a=b
        b = c; // 更新b=c
    }

    print(&c,n); // 输出第n个斐波那契数列数
    return;
}

void fibmain() {
    color(14);printf(">------------------------高精度斐波那契启动------------------------<\n");
    tip;printf("温馨提示:本功能支持斐波那契数列前30000项!\n");
    int n;
    run;printf("请输入要计算的斐波那契数列的项数:");re;
    scanf("%d", &n);
    fib(n);
    color(8);printf("\n运算完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
    return ;
}

void help(){
    color(14);printf("—————————————————————————高精度计算器使用说明——————————————————————————\n");re;
    printf("一、本高精度计算器的功能\n"
    "1.科学计算器2.高精度加法3.高精度减法4.高精度乘法5.高精度除法6.高精度阶乘7.高精度小数8.高精度斐波那契\n\n"

    "二、本计算器的使用流程\n"
    "1.在菜单页面选择一个功能选项或直接退出\n"
    "2.功能启动,输入进行运算的数。\n"
    "3.运算完毕,输出结果\n"
    "4.选择下一个功能选项或退出\n\n"

    "三、本计算器各功能的使用方法\n"
    "1.科学计算器\n"
    "本功能以科学计数法的形式输出。\n"
    "进入功能后选择运算列表:1.加 2.减 3.乘 4.除,回车确认。\n"
    "输入第一个数,回车确认。\n"
    "输入第二个数,回车确认。\n"
    "即得到答案,按任意键返回菜单。\n\n"

    "2.高精度加法\n"
    "本功能支持100000位以内的正整数相加!\n"
    "若要从txt文件输入请将存有两个数的num.txt放入此文件夹(注意:两个数字换行隔开)。\n"
    "输入是否从txt读入(0.否,1.是),回车确认。(非1均默认为否)\n"
    "不从txt读入则输入第一个数,回车确认。输入第二个数,回车确认。\n"
    "得到答案,选择是否将答案保存为txt(0.否,1.是)。(非1均默认为否)\n"
    "选择是则答案保存至文件夹内ans.txt,按任意键返回菜单。\n\n"

    "3.高精度减法\n"
    "本功能支持100000位以内的正整数相减!用法与高精度加法相同。\n\n"

    "4.高精度乘法\n"
    "本功能支持1000位以内的正整数相乘!用法与高精度加法相同。\n\n"

    "5.高精度除法\n"
    "本功能支持10000位以内的正整数相除!答案由商和余数构成,需要小数请移步高精度小数!用法与高精度加法相同。\n\n"

    "6.高精度阶乘\n"
    "本功能支持25000以内的正整数阶乘!\n"
    "输入正整数,回车确认。\n"
    "得到答案,选择是否将答案保存为txt(0.否,1.是)。(非1均默认为否)\n"
    "选择是则答案保存至文件夹内ans.txt,按任意键返回菜单。\n\n"

    "7.高精度小数\n"
    "本功能支持分子和分母在24位以内的分数,包括真分数和假分数!\n"
    "输入分子/分母,回车确认。\n"
    "得到答案,按任意键返回菜单。\n"

    "8.高精度斐波那契\n"
    "本功能支持输出斐波那契数列前30000项!\n"
    "输入要计算的斐波那契数列的项数,回车确认。\n"
    "得到答案,选择是否将答案保存为txt(0.否,1.是)。(非1均默认为否)\n"
    "选择是则答案保存至文件夹内ans.txt,按任意键返回菜单。\n\n"

    "9.帮助\n"
    "显示使用说明\n\n"

    "0.退出\n"
    "退出程序\n"
    );
    color(14);printf("————————————————————————以上为高精度计算器使用说明————————————————————————\n");re;
    color(8);printf("\n显示完毕!即将自动返回菜单!\n");color(16);
    system("PAUSE");
return;

}


//>----------------------主函数----------------------<
int main() {
    int s;// 选择的功能
    color(3); //封面颜色
    printf("\n  /———————————————————[欢迎使用高精度计算器]——————————————————\\ \n");
    printf(" /                                                             \\\n");
    printf("| 高精度计算器           版本:%s           作者:dinosaur    \t|\n",version);
    printf("| High-precision calculator                 version:%s   \t|\n",version);
    printf(" \\                                                             /\n");
    printf("  \\———————————————————————————————————————————————————————————/ \n");
    do{color(14);//菜单颜色
    printf("\n  /—————————————————————————功能菜单——————————————————————————\\ \n");
    printf(" /                                                             \\\n");
    printf("|1.科学计算器\t\t2.高精度加法\t\t3.高精度减法\t|\n");
    printf("|4.高精度乘法\t\t5.高精度除法\t\t6.高精度阶乘\t|\n");
    printf("|7.高精度小数\t\t8.高精度斐波那契\t9.帮助\t\t|\n");
    printf("|\t\t\t0.退出\t\t\t\t\t|\n");
    printf(" \\                                                             /\n");
    printf("  \\———————————————————————————————————————————————————————————/ \n");
    choose;printf("\t\t\t请选择菜单功能:");re;
        scanf("%d",&s);
        putchar(10);//换行
        if ((0 == s)) {
            color(14);printf("\n  *——————————————————谢谢使用CTF高精度计算器——————————————————* \n\n");re;
            return 0;
        }
        if (s < 0 || s > 9) {// 只允许选择菜单栏内的数字,体现安全性
            color(12);printf("\t\t\t请输入合理的选项!\n");
            choose;printf("\t\t\t请重新选择菜单功能:");re;
            scanf("%d",&s);
        }
        switch (s) {//分支结构进入对应函数
            case 1:
                easy();
                break;
            case 2:
                add();
                break;
            case 3:
                minus();
                break;
            case 4:
                multi();
                break;
            case 5:
                divi();
                break;
            case 6:
                fact();
                break;
            case 7:
                floats();
                break;
            case 8:
                fibmain();
                break;
            case 9:
                help();
                break;           
            case 0:
                color(14);printf("\n  *——————————————————[谢谢使用高精度计算器]——————————————————* \n\n");re;
                return 0;
        }
    }while(s!=0);
    return 0;
}

  • 32
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值