计算机中采用浮点数表示所有实数,但这意味着精度丢失。例如无法精确表示“1/3”。
NowCoder最近要处理很多金融问题,这些账目不允许出现精度丢失,因为差之毫厘谬之千里。你能帮他实现一套分数的计算器吗?
输入包含多组数据。
每组数据一行,包含两个分数和一个运算符,中间用空格隔开。
其中分子与分母均为不大于30的正整数。
对应每一组数据,输出两个分数的计算结果。
要求输出最简分数,即分子与分母互质。
1/3 2/3 +<br/>1/5 1/4 -<br/>1/2 1/3 *<br/>2/3 4/3 /
1/1<br/>-1/20<br/>1/6<br/>1/2
#include<stdio.h>
int gcd(int x, int y)
{
if (y%x == 0)
return x;
return gcd(y%x, x);
}
int main()
{
int nom1, nom2, den1, den2,
den, newNom1, newNom2,
tmpNom, tmpDen, tmpGcd,
resNom, resDen;
char op;
while (~scanf("%d/%d%d/%d %c", &nom1, &den1,&nom2,&den2,&op))
{
den = den1*den2 / gcd(den1, den2);
newNom1 = nom1*den / den1;
newNom2 = nom2*den / den2;
switch (op)
{
case '+':
tmpNom = newNom1 + newNom2;
tmpDen = den;
break;
case '-':
tmpNom = newNom1 - newNom2;
tmpDen = den;
break;
case '*':
tmpNom = nom1*nom2;
tmpDen = den1*den2;
break;
case '/':
tmpNom = nom1*den2;
tmpDen = den1*nom2;
break;
}
tmpGcd = gcd(tmpNom, tmpDen);
resNom = tmpNom / tmpGcd;
resDen = tmpDen / tmpGcd;
resNom = resNom*resDen < 0 ? -abs(resNom) : abs(resNom);
resDen = abs(resDen);
printf("%d/%d\n",resNom,resDen);
}
return 0;
} 实现思路:
1、构造分数类;
2、实现四则运算;
3、利用 “辗转相除法 ”思想构造求最大公约数的算法;
4、利用最大公约数进行月份简化;
5、输出;
另外需要注意的是,尽量减少分数简化(约分)次数,我之前几次超时,原因是构造分数时就进行一次约分。实际上只需要在 输出前 约分 就行;
以下代码仅供参考:
import java.util.Scanner;
/**
* @author MemoryC
* */
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNext()) {
String[]aStrings=scanner.next().split("/");
String[] bString=scanner.next().split("/");
char operation=scanner.next().charAt(0);
Fraction a=new Fraction(Integer.parseInt(aStrings[0]), Integer.parseInt(aStrings[1]));
Fraction b=new Fraction(Integer.parseInt(bString[0]), Integer.parseInt(bString[1]));
Fraction c=null;
switch (operation) {
case '+':
c=Fraction.add(a, b);
break;
case '-':
c=Fraction.cut(a, b);
break;
case '*':
c=Fraction.multiply(a, b);
break;
case '/':
c=Fraction.divide(a, b);
break;
default:
break;
}
c.Simplify();
System.out.println(c);
}
scanner.close();
}
static class Fraction{
int mom=1;
int son=0;
boolean negtive=false;
public Fraction(int son,int mom) {
if(son<0) {
son=-son;
negtive=true;
}else if(son==0) {
mom=1;
}
this.son=son;
this.mom=mom;
}
public String toString() {
return negtive?("-"+son+"/"+mom):(son+"/"+mom);
}
static int getCommonDivisor(int a,int b) {
if(a<b) {
return getCommonDivisor(b,a);
}
int aa=a;
int bb=b;
while(aa%bb!=0) {
int r=aa%bb;
aa=bb;
bb=r;
}
return bb;
}
void Simplify() {
if(son==mom) {
son=1;
mom=1;
}else {
int common=getCommonDivisor(son, mom);
son=son/common;
mom=mom/common;
}
}
static Fraction add(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.mom,bs=b.son,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bm+bs*am;
return new Fraction(cs,cm);
}
static Fraction cut(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.mom,bs=-b.son,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bm+bs*am;
return new Fraction(cs,cm);
}
static Fraction multiply(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.mom,bs=b.son,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bs;
return new Fraction(cs,cm);
}
static Fraction divide(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.son,bs=b.mom,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bs;
return new Fraction(cs,cm);
}
}
}
#include <stdio.h>
int gcd(int x,int y) //求最大公约数
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
void add(int a1,int a2,int b1,int b2)
{
int n1=a1*b2+a2*b1;
int n2=a2*b2;
int temp=gcd(n1,n2);
if(temp<0)
temp=-temp;
printf("%d/%d\n",n1/temp,n2/temp);
}
void mul(int a1,int a2,int b1,int b2)
{
int n1=a1*b1;
int n2=a2*b2;
int temp=gcd(n1,n2);
if(temp<0)
temp=-temp;
printf("%d/%d\n",n1/temp,n2/temp);
}
int main()
{
int a1,a2,b1,b2; //第一个数和第二个数得分子和分母
char ch;
while(scanf("%d/%d %d/%d %c",&a1,&a2,&b1,&b2,&ch)!=EOF)
{
//printf("%d %d %d %d\n",a1,a2,b1,b2);
switch(ch)
{
case '+':
{
add(a1,a2,b1,b2);
break;
}
case '-':
{
add(a1,a2,-b1,b2);
break;
}
case '*':
{
mul(a1,a2,b1,b2);
break;
}
case '/':
{
mul(a1,a2,b2,b1);
break;
}
}
}
return 0;
} #include<stdio.h>
int gcd(int x,int y)
{
return !y? x>0?x:-x:gcd(y,x%y);
}
int main()
{
int a1,b1,a2,b2;
char c;
while(scanf("%d/%d %d/%d %c",&a1,&b1,&a2,&b2,&c)!=-1)
{
int A,B,C;
switch(c)
{
case '+':
A=a1*b2+a2*b1;
B=b1*b2;
C=gcd(A,B);
printf("%d/%d\n",A/C,B/C);
break;
case '-':
A=a1*b2-a2*b1;
B=b1*b2;
C=gcd(A,B);
printf("%d/%d\n",A/C,B/C);
break;
case '*':
A=a1*a2;
B=b1*b2;
C=gcd(A,B);
printf("%d/%d\n",A/C,B/C);
break;
case '/':
A=a1*b2;
B=a2*b1;
C=gcd(A,B);
B<0?printf("%d/%d\n",-A/C,-B/C):printf("%d/%d\n",A/C,B/C);
break;
default:break;
}
}
return 0;
} //水题,不过做这感觉比较爽:)#include <stdio.h>int Simplify(inta, intb);int main(){int numer0, denom0, numer1, denom1;int numer2, denom2;char oper[1];int res = 0;while(scanf("%d/%d %d/%d %c", &numer0, &denom0, &numer1, &denom1, &oper[0])!=EOF){if(oper[0]=='+'||oper[0]=='-'){denom2 = denom0*denom1;if(oper[0]=='+'){numer2 = numer0*denom1 + numer1*denom0;}else{numer2 = numer0*denom1 - numer1*denom0;}}elseif(oper[0]=='*'||oper[0]=='/'){if(oper[0]=='*'){numer2 = numer0*numer1;denom2 = denom0*denom1;}else{numer2 = numer0*denom1;denom2 = denom0*numer1;}}res = Simplify(numer2, denom2);denom2 /= res;numer2 /= res;if(denom2<0){printf("-%d/%d\n", numer2, -denom2);}else{printf("%d/%d\n", numer2, denom2);}}return0;}int Simplify(int a, int b){int t;while(b!=0){t = a % b;a = b;b = t;}return a;}
//不服,给我一个超时的理由!importjava.util.Scanner;publicclassMain {publicstaticvoidmain(String[] args) {Scanner in = newScanner(System.in);while(in.hasNext()){String s1=in.next(),s2=in.next(),op=in.next();String[] split1 = s1.split("/"),split2 = s2.split("/");intup1=Integer.valueOf(split1[0]),down1=Integer.valueOf(split1[1]);intup2=Integer.valueOf(split2[0]),down2=Integer.valueOf(split2[1]);intminComm = down1*down2/maxCommon(down1,down2);intup=0,down=0;switch(op) {case"+":inttimes1=minComm/down1,times2=minComm/down2;down=minComm;up=up1*times1+up2*times2;intmaxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;break;case"-":times1=minComm/down1;times2=minComm/down2;down=minComm;up=up1*times1-up2*times2;if(up<0){maxComm = maxCommon(down,up*=-1);up/=maxComm;down/=maxComm;up*=-1;}elseif(up==0){System.out.println("ERROR");}else{maxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;}break;case"*":up=up1*up2;down=down1*down2;maxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;break;case"/":up=up1*down2;down=down1*up2;maxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;break;}System.out.printf("%d/%d\n",up,down);}}publicstaticintmaxCommon(intm,intn){if(m<n){inttemp=n;n=m;m=temp;}if(m%n==0)returnn;elsereturnmaxCommon(n,m%n);}}
#include <stdio.h>
int zdgys(int a,int b)
{
int r;
if(a==0)
{
return a;
}
else
{
while(b!=0)
{
r=a%b;
a=b;
b=r;
}
return a;
}
}
int zxgbs(int a,int b)
{
return a*b/zdgys(a,b);
}
int main()
{
char a[6],b[6],c,tab;
int afz,afm,bfz,bfm,i,j,m,n,temp;
while(scanf("%s%s%c%c",a,b,&tab,&c)!=EOF)
{
afz=0;afm=0;bfz=0;bfm=0;
for(i=0;a[i]!='/';i++)
{
afz=afz*10+a[i]-'0';
}
for(;a[i]!='\0';i++)
{
if(a[i]>='0'&&a[i]<='9')
{
afm=afm*10+a[i]-'0';
}
}
for(i=0;b[i]!='/';i++)
{
bfz=bfz*10+b[i]-'0';
}
for(;b[i]!='\0';i++)
{
if(b[i]>='0'&&b[i]<='9')
{
bfm=bfm*10+b[i]-'0';
}
}
if(c=='+')
{
m=afz*zxgbs(afm,bfm)/afm+bfz*zxgbs(afm,bfm)/bfm;
n=zxgbs(afm,bfm);
printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n));
}
else if(c=='-')
{
m=afz*zxgbs(afm,bfm)/afm-bfz*zxgbs(afm,bfm)/bfm;
n=zxgbs(afm,bfm);
if(m>0)
{
printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n));
}
else if(m==0)
{
printf("0\n");
}
else if(m<0)
{
printf("-%d/%d\n",-m/zdgys(-m,n),n/zdgys(-m,n));
}
}
else if(c=='*')
{
m=afz*bfz;n=afm*bfm;
printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n));
}
else if(c=='/')
{
temp=bfz;bfz=bfm;bfm=temp;
m=afz*bfz;n=afm*bfm;
printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n));
}
}
return 0;
} #include<bits/stdc++.h>
using namespace std;
int main()
{
int a1,b1,a2,b2,g;
char _1,_2,op;
while(cin>>a1>>_1>>b1>>a2>>_2>>b2>>op)
{
switch(op)
{
case'+':a1=a1*b2+b1*a2;
b1*=b2;
g=abs(__gcd(a1,b1));
cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl;
break;
case'-':a1=a1*b2-b1*a2;
b1*=b2;
g=abs(__gcd(a1,b1));
cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl;
break;
case'*':a1*=a2;
b1*=b2;
g=abs(__gcd(a1,b1));
cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl;
break;
case'/':
a1*=b2;
b1*=a2;
g=abs(__gcd(a1,b1));
cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl;
break;
default:break;
}
}
return 0;
} #include<bits/stdc++.h>
using namespace std;
inline int stringint(string x)
{
long long temp=0;
int a=1;
int length=x.size();
for(int i=length-1;i>=0;i--)
{
temp+=a*(x[i]-'0');
a*=10;
}
return temp;
}
inline void Print(int x1,int x2,int y1,int y2,string h3)
{
if(h3=="+"||h3=="-")
{
while(x2!=y2)
{
int temp=x2;
x2*=y2;
x1*=y2;
y2*=temp;
y1*=temp;
}
if(h3=="+")
{
int g;
int res=x1+y1;
while((g=__***(res,x2))!=1)
{
res/=g;
x2/=g;
}
cout<<res<<"/"<<x2<<endl;
}
else
{
int g,d=1;
int res=x1-y1;
if(res<0)
{
d=0;
res=-res;
}
while((g=__***(res,x2))!=1)
{
res/=g;
x2/=g;
}
if(d)
{
cout<<res<<"/"<<x2<<endl;
}
else
{
cout<<"-"<<res<<"/"<<x2<<endl;
}
}
}
else if(h3=="*")
{
int g;
int x3=x1*y1;
int x4=x2*y2;
while((g=__***(x3,x4))!=1)
{
x3/=g;
x4/=g;
}
cout<<x3<<"/"<<x4<<endl;
}
else
{
int g;
int x3=x1*y2;
int x4=x2*y1;
while((g=__***(x3,x4))!=1)
{
x3/=g;
x4/=g;
}
cout<<x3<<"/"<<x4<<endl;
}
}
int main()
{
string h1,h2,h3;
int i,j;
while(cin>>h1>>h2>>h3)
{
for(i=0;;i++)
{
if(h1[i]=='/') break;
}
int x1=stringint(h1.substr(0,i));
int x2=stringint(h1.substr(i+1));
for(j=0;;j++)
{
if(h2[j]=='/') break;
}
int y1=stringint(h2.substr(0,j));
int y2=stringint(h2.substr(j+1));
Print(x1,x2,y1,y2,h3);
}
} #include<cstdio>
(802)#include<cstdlib>
int a,b,c,d;
char x;
void ans()
{
if(x=='+')
{
int k=b*d,z=a*d+b*c;
a=z,b=k;
}
else if(x=='-')
{
int k=b*d,z=a*d-b*c;
a=z,b=k;
}
else if(x=='*')
{
int k=b*d,z=a*c;
a=z,b=k;
}
else if(x=='/')
{
int k=b*c,z=a*d;
a=z,b=k;
}
int k=abs(a)>abs(b)?abs(b):abs(a);
if(abs(a)==1 || abs(b)==1) return ;
for(int i=k;i>1;i--)
{
if(abs(a)%i==0 && abs(b)%i==0) {a=a/i;b=b/i;return;}
}
return ;
}
int main()
{
while(scanf("%d/%d %d/%d %c",&a,&b,&c,&d,&x)!=EOF)
{
ans();
printf("%d/%d\n",a,b);
}
return 0;
}
本题的关键是最大公因数、最小公倍数的求解。
两数的最大公因数求解常用辗转相除法,比如a,b两数(假设a >= b)
while (a % b != 0) {
b’ 赋值为 a / b 余数 (即 a % b)
a‘ 赋值为 b
a = a’, b = b'
} 两数的最小公倍数求解有个数学规律
a、b最小公倍数 = a * b / (a、b最大公因数)
#include <iostream>
(720)#include <math.h>
using namespace std;
// 求number1、number2的最大公因数
int gcd(int number1, int number2) {
int tempNum = 0;
//保持number1不小于number2
if (number1 < number2) {
//借助tempNum,将number1、number2进行交换
tempNum = number1;
number1 = number2;
number2 = tempNum;
}
//判断number1是否能整除number2
while (number1 % number2 != 0) {
//ba余数赋给tempNum
tempNum = number1 % number2;
//把number2赋给number1,tempNum赋给number2
//由于进行求余时,number2是除数,tempNum是余数,所以number2 > tempNum
//赋值操作后继续维持了 number1 > number2
number1 = number2;
number2 = tempNum;
}
return number2;
}
// 求number1、number2的最小公倍数
int lcm(int number1, int number2) {
//最小公倍数 = 两数相乘 / 最大公因数
return number1 * number2 / gcd(number1, number2);
}
int main(int argc, const char * argv[]) {
char op = '\0';
// 分数numerator1/denominator1,参数1 分数numerator2/denominator2 参数2
int numerator1 = 1, denominator1 = 1, numerator2 = 1, denominator2 = 1;
//scanf返回值为正确输入数据的变量个数,当一个变量都没有成功获取数据时,此时返回-1
while (scanf("%d/%d %d/%d %c", &numerator1, &denominator1, &numerator2, &denominator2, &op) != - 1) {
//记录结果是否为负数
bool flag = false;
//分数numerator3/denominator3,结果
int numerator3 = 0, denominator3 = 0;
if (op == '+') {
//处理分数加法,先分母同分,然后分子与分母交叉相乘
denominator3 = denominator1 * denominator2;
numerator3 = numerator1 * denominator2 + numerator2 * denominator1;
}
if (op == '-') {
//处理分数减法,先分母同分,然后分子与分母交叉相乘
denominator3 = denominator1 * denominator2;
numerator3 = numerator1 * denominator2 - numerator2 * denominator1;
if (numerator3 < 0) {
//这里单独记录负号,是因为求解公因数、公倍数是不能有负数
flag = true;
numerator3 = -numerator3;
}
}
if (op == '*') {
//处理分数乘法,分母相乘,分子相乘
denominator3 = denominator1 * denominator2;
numerator3 = numerator1 * numerator2;
}
if (op == '/') {
//处理分数除法,分母1 分子2 相乘作分母,分子1 分母2 相乘 作分子
denominator3 = denominator1 * numerator2;
numerator3 = numerator1 * denominator2;
}
if (numerator3 == 0) {
printf("0\n");
} else {
//分子、分母分别除最大公因数进行约分
int tempNum = gcd(numerator3, denominator3);
numerator3 /= tempNum;
denominator3 /= tempNum;
//如果是减法可能产生负数,因此需要输出负号
printf((flag ? "-%d/%d\n" : "%d/%d\n"), numerator3, denominator3);
}
}
return 0;
}
//30以内的质数只有2,3,5,7,11,13,17,19,23,29
#include <stdio.h>
#include <stdlib.h>
int prime[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
int is_relative(int a, int b)
{
for(int i = 0; i < 10; i++)
{
if(a % prime[i] == 0 && b % prime[i] == 0)
return prime[i];//不互质,有因数prime[i]
}
return 1;//互质
}
int main()
{
int a1, b1, a2, b2;
char sign;
int temp1, temp2;
while(~scanf("%d/%d %d/%d %c", &a1, &b1, &a2, &b2, &sign))
{
int x;
if(sign == '+')
{
temp2 = b1 * b2;
temp1 = a1*b2 + a2*b1;
}
else if(sign == '-')
{
temp2 = b1 * b2;
temp1 = a1*b2 - a2*b1;
}
else if(sign == '*')
{
temp2 = b1 * b2;
temp1 = a1 * a2;
}
else
{
temp2 = a2 * b1;
temp1 = a1 * b2;
}
if(temp1 == temp2)
temp1 = temp2 = 1;
while((x = is_relative(temp1, temp2)) != 1)
{
temp1 = temp1/x;
temp2 = temp2/x;
}
printf("%d/%d\n", temp1, temp2);
}
} //可能不是你的程序真的超时,而是你的输入没有加入!=EOF,真的牛皮
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
int MinCommonMultiple(int a, int b)
{
int minnum = 0;
for (int i = max(a,b);;i++)
{
if (i%a == 0 && i%b == 0)
{
minnum = i;
break;
}
}
return minnum;
}
int MaxConventionNumber(int a, int b)
{
int maxnum = 0;
for (int i = min(a, b);i >= 2;i--)
{
if (a%i == 0 && b%i == 0)
{
maxnum = i;
break;
}
}
return maxnum;
}
//约分
void reduction(int &a0, int &a1)
{
if (a0 < 0)
{
a0 = -a0;
cout << '-';
}
if (a0 == 0)
{
cout << a0 << endl;
return;
}
//得到最大公约数
int maxnum = MaxConventionNumber(a0, a1);
if (maxnum != 0)
{
//约分
a0 /= maxnum;
a1 /= maxnum;
}
cout << a0 << '/' << a1 << endl;
}
//通分
void reverse_red(int &a0, int &a1, int &b0, int &b1)
{
if (a1 != b1)
{
int minnum = MinCommonMultiple(a1, b1);
a0 = minnum / a1 * a0;
b0 = minnum / b1 * b0;
a1 = b1 = minnum;
}
}
int main()
{
string str0, str1;
char ch4;
int a0, a1, b0, b1;
while (scanf_s("%d/%d %d/%d %c",&a0,&a1,&b0,&b1,&ch4)!=EOF)
{
if (ch4 == '+')
{
reverse_red(a0, a1, b0, b1); //通分
a0 += b0;
reduction(a0, a1); //约分
}
else if (ch4 == '-')
{
reverse_red(a0, a1, b0, b1);
a0 -= b0;
reduction(a0, a1);
}
else if (ch4 == '*')
{
a0 *= b0;
a1 *= b1;
reduction(a0, a1);
}
else if (ch4 == '/')
{
a0 *= b1;
a1 *= b0;
reduction(a0, a1);
}
else
{
cout << "The operation you inputed was failed." << endl;
}
}
return 0;
} //超时 感觉是死循环另外呀 貌似java全超时了
import java.io.*;
import java.util.*;
public class Test1012Caculate {
public static void main(String[] args) {
Scanner in= new Scanner(new BufferedInputStream(System.in));
while (in.hasNext()) {
String []a=in.next().split("/");
String []b=in.next().split("/");
int a1=Integer.parseInt(a[0]);
int b1=Integer.parseInt(a[1]);
int a2=Integer.parseInt(b[0]);
int b2=Integer.parseInt(b[1]);
char op=in.next().charAt(0);
switch (op) {
case '+':
{
int x=a1*b2+a2*b1;
int y=b1*b2;
int gcd=getGcd(x, y);
x=x/gcd;
y=y/gcd;
System.out.printf("%d/%d\n",x,y);
break;
}
case '-':
{
int x=a1*b2-a2*b1;
int y=b1*b2;
int gcd=Math.abs(getGcd(x, y));
x=x/gcd;
y=y/gcd;
System.out.printf("%d/%d\n",x,y);
break;
}
case '*':
{
int x=a1*a2;
int y=b1*b2;
int gcd=getGcd(x, y);
x=x/gcd;
y=y/gcd;
System.out.printf("%d/%d\n",x,y);
break;
}
case '/':
{
int x=a1*b2;
int y=b1*a2;
int gcd=getGcd(x, y);
x=x/gcd;
y=y/gcd;
System.out.printf("%d/%d\n",x,y);
break;
}
default:
break;
}
}
}
public static int getGcd(int p,int q) {
if(p%q==0){
return q;
}
int r= p%q;
return getGcd(q,r);
}
}