分数的四则运算

 如果k属于集合Q,Q={ p/q | p是整数,q是正整数,p与q互质},那么k是有理数,Q是有理数集。

 也就是说,有理数都能表示成分数的形式,下面用分数的四则运算来实现有理数的四则运算。

 首先记几个单词:fraction 分数,denominator 分母,numerator 分子,sign 符号

 下面会用到求最大公约数函数gcd,查看定义请戳这里

 也会用到可变参数函数,如果不清楚,请戳这里

 

 首先定义分数结构以及一些需要的宏

 1 #define abs(a)         ((a)>=0?(a):-(a))//绝对值
 2 #define swap(a,b,type) do{ type t;t=a;a=b;b=t; }while(0)//交换变量
 3 #define sgn(a)         ((a)>0?1:((a)<0?-1:0))//符号函数
 4 
 5 typedef long DataType;
 6 typedef struct
 7 {
 8     DataType nume;//分子为整数
 9     DataType deno;//分母为正整数
10 }Frc;

 两个分数相加,返回和

 1 Frc frc_add(Frc *opd1,Frc *opd2)
 2 {
 3     Frc frc;
 4     DataType t;
 5     assert(opd1&&opd2);
 6     //判断其中的一个分数是否为0 
 7     if(0==opd1->nume)
 8         return *opd2;
 9     if(0==opd2->nume)
10         return *opd1;
11     if(opd1->deno==opd2->deno)//如果分母相等 
12     {
13         frc.nume=opd1->nume+opd2->nume;
14         frc.deno=opd1->deno;
15     }
16     else//如过分母不同
17     {
18         frc.nume=opd1->nume*opd2->deno+opd1->deno*opd2->nume;
19         frc.deno=opd1->deno*opd2->deno;
20     }
21     if(0==frc.nume)//如果结果为0 
22         return frc;
23     //约分 
24     t=gcd(abs(frc.nume),frc.deno);
25     if(1==t)
26         return frc;
27     frc.nume/=t;
28     frc.deno/=t;
29     return frc;
30 }

 

 两个分数相减,返回差

1 Frc frc_sub(Frc *opd1,Frc *opd2)
2 {
3     Frc t;
4     assert(opd1&&opd2);
5     
6     t=*opd2;
7     t.nume=-t.nume;
8     return frc_add(opd1,&t);
9 }

 两个分数相乘,返回积

 1 Frc frc_mul(Frc *opd1,Frc *opd2)
 2 {
 3    Frc frc={0,1};//规定了分母不能为0 
 4    DataType t;
 5    assert(opd1&&opd2);
 6    
 7    if(0==opd1->nume||0==opd2->nume)//如果其中一个分数为0 
 8        return frc;
 9    frc.nume=opd1->nume*opd2->nume;
10    frc.deno=opd1->deno*opd2->deno;
11    
12    t=gcd(abs(frc.nume),frc.deno);//约分 
13    if(1==t)
14        return frc;
15    frc.nume/=t;
16    frc.deno/=t;
17    return frc; 
18 }

 两个分数相除,返回商

 1 Frc frc_div(Frc *opd1,Frc *opd2)
 2 {
 3     Frc frc={0,1};//分母规定不能为0
 4     int sign;
 5     assert(opd1&&opd2);
 6     
 7     if(0==opd2->nume)//如果除数为0 
 8         exit(1);
 9     if(0==opd1->nume)//如果被除数为0 
10         return frc;
11         
12     sign=sgn(opd2->nume);//保存opd2符号 
13     frc=*opd2;
14     swap(frc.nume,frc.deno,int);
15     frc.deno=abs(frc.deno);//保证分母为正 
16     frc.nume*=sign;
17     return frc_mul(opd1,&frc);
18 }

求倒数

Frc frc_inverse(Frc *opd)
{
    Frc frc;
    int sign;
    assert(opd);
    
    if(0==opd->nume)//分子为0,没有倒数 
        exit(1);
    sign=sgn(opd->nume);//保存符号 
    frc.nume=opd->deno*sign;
    frc.deno=abs(opd->nume);
    return frc;
}

分数的n次幂,n是整数,返回其n次幂

 1 Frc frc_pow(Frc *opd,int n)
 2 {
 3     int t=n;
 4     int sign;
 5     Frc frc={0,1};
 6     assert(opd);
 7     
 8     if(n==0)
 9         return frc;
10     if(0==opd->nume)
11         if(n>0)
12             return frc;
13         else//0没有负数次方 
14             exit(1);
15     frc=*opd;
16     if(n<0)//如果是负次方 
17         frc=frc_inverse(opd);
18     if(1!=opd->nume)//分子n次方 
19         while(--t)
20             frc.nume*=opd->nume;
21     if(1!=opd->deno)//分母n次方 
22         while(--n)
23             frc.deno*=opd->deno;
24     return frc;
25 }

读入分数,n为要读入分数的个数,...的使用方法和scanf类似,函数返回输入分数的个数

 1 int frc_input(int n,...)
 2 {
 3     int cnt=0;
 4     Frc *frc;
 5     va_list parg;
 6     DataType t;
 7     
 8     va_start(parg,n);
 9     while(n--)
10     {
11         frc=va_arg(parg,Frc*);
12         scanf("%d",&frc->nume); 
13         if(getchar()=='/')//判断是否需要输入分母 
14             scanf("%d",&frc->deno);
15         else
16             frc->deno=1;
17         if(frc->deno==0)//如果分母为0 
18             return 0;
19         if(frc->deno<0)//如果分母为负 
20         {
21             frc->nume=-frc->nume;
22             frc->deno=abs(frc->deno);
23         }
24         t=gcd(abs(frc->nume),frc->deno);//约分 
25         if(1!=t)
26         {
27             frc->nume/=t;
28             frc->deno/=t;
29         }
30         cnt++;
31     }va_end(parg);
32     return cnt;
33 }

输出分数,方法和printf类似,用%r输入分数,返回输出分数的个数

 1 int frc_print(char *format,...)
 2 {
 3     int cnt=0;//记录输出了几个分数
 4     Frc frc;
 5     va_list parg;
 6     assert(format);
 7     
 8     va_start(parg,format);
 9     while(*format)
10     {
11         switch(*format)
12         {
13             case '%':
14                 if('%'==*(format+1))//如果是%%,则输出% 
15                 {
16                     putchar('%');
17                     format++;
18                 }
19                 else if('r'==*(format+1))
20                 {
21                     frc=va_arg(parg,Frc);
22                     printf("%d",frc.nume);
23                     if(1!=frc.deno)//判断是否需要输出分母 
24                         printf("/%d",frc.deno);
25                     cnt++;
26                     format++;
27                 }
28                 else
29                     putchar(*format);
30                 break;
31             default:
32                 putchar(*format);
33                 break;
34         }
35         format++;
36     }va_end(parg);
37     return cnt;
38 }

下面是测试程序

#include<stdio.h>
#include<stdarg.h>
#include<assert.h>
#include<stdlib.h>

int main(int argc,char *argv[])
{
    int instr;
    Frc frc1,frc2;
    
    head();
    while(1)
    {
        printf("\ninstruction:");
        scanf("%d",&instr);
        switch(instr)
        {
            case 0://退出
                goto end_pro;case 1://输入 
                frc_input(2,&frc1,&frc2);
                break;
            case 2://输出 
                frc_print("frc1 = %r frc2 = %r",frc1,frc2);
                break;
            case 3://
                frc_print("%r + %r = %r",frc1,frc2,frc_add(&frc1,&frc2));
                break;
            case 4://
                frc_print("%r - %r = %r",frc1,frc2,frc_sub(&frc1,&frc2));
                break;
            case 5://
                frc_print("%r * %r = %r",frc1,frc2,frc_mul(&frc1,&frc2));
                break;
            case 6://
                frc_print("%r / %r = %r",frc1,frc2,frc_div(&frc1,&frc2));
                break;
            case 7://倒数
                frc_print("inverse %r = %r",frc1,frc_inverse(&frc1));
                break;
            case 8://3次幂 
                 frc_print("(%r)^3=%r",frc1,frc_pow(&frc1,3));
                 break;
            case 9:
                head();
                break;
            default:
                break;
        }
    }
    end_pro:
    return 0;
}

 

posted @ 2015-11-19 19:14  _Bin  阅读(767)  评论(0编辑  收藏  举报