本题要求编写程序,计算 2 个有理数的和、差、积、商。
输入格式:
输入在一行中按照 a1/b1 a2/b2
的格式给出两个分数形式的有理数,其中分子和分母全是整型范围内的整数,负号只可能出现在分子前,分母不为 0。
输出格式:
分别在 4 行中按照 有理数1 运算符 有理数2 = 结果
的格式顺序输出 2 个有理数的和、差、积、商。注意输出的每个有理数必须是该有理数的最简形式 k a/b
,其中 k
是整数部分,a/b
是最简分数部分;若为负数,则须加括号;若除法分母为 0,则输出 Inf
。题目保证正确的输出中没有超过整型范围的整数。
输入样例 1:
2/3 -4/2
输出样例 1:
2/3 + (-2) = (-1 1/3)
2/3 - (-2) = 2 2/3
2/3 * (-2) = (-1 1/3)
2/3 / (-2) = (-1/3)
输入样例 2:
5/3 0/6
输出样例 2:
1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf
题解如下:
17/20 case2错误,看网上好像说要先化简再运算,有机会尝试一下
我的方法是用数组存储分数的分子和分母,便于取用
进行加减法计算时需要先通分,求最小公倍数;数据化简时需要约分,求最大公约数,用到了辗转相除法
乘法和除法的本质是一样的,进行除法运算时,先判断除数是否为零,为0的话直接返回Inf,不为0的话,先将除数求倒,也就是交换分子分母的位置,再进行乘法运算,但是如果分子是负数的话就需要将正负号也交换位置,否则负号就会跑到分母上去,出现计算错误。
在对数据进行化简时可分为3种情况:
- 分子为0:整个分数直接为0;
- 分子小于分母:此时分子可能为负数,我为了简便直接将分子取反再调用化简函数,return时加上符号就行;再对数据求最大公因数约分;
- 分子大于分母:先求整数部分,令分子等于余数,再对分子分母求最大公约数约分。
/**
* 2024/03/013
* 17/20
* TODO: 一开始就化简
*/
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.on("line", function (data) {
const dataArr = data.split(" ");
// 第一个数
let mol = [Number(dataArr[0].split("/")[0]), dataArr[0].split("/")[1]];
// 第二个数
let den = [Number(dataArr[1].split("/")[0]), dataArr[1].split("/")[1]];
let molData = simplify(mol[0], mol[1]);
let denData = simplify(den[0], den[1]);
console.log(`${molData} + ${denData} = ${addOrSub(mol, den, true)}`);
console.log(`${molData} - ${denData} = ${addOrSub(mol, den, false)}`);
console.log(
`${molData} * ${denData} = ${multipleOrDivision(mol, den, true)}`,
);
const diviRes = multipleOrDivision(mol, den, false);
if (diviRes === " Inf") {
console.log(diviRes);
} else {
console.log(`${molData} / ${denData} = ${diviRes}`);
}
});
/**
* 加法/减法
* @param first
* @param second
* @param flg
* @returns {number|string|number}
*/
function addOrSub(first, second, flg) {
const minRes = getMinMultiple(first[1], second[1]);
const mol = flg
? (first[0] * minRes) / first[1] + (second[0] * minRes) / second[1]
: (first[0] * minRes) / first[1] - (second[0] * minRes) / second[1];
return simplify(mol, minRes);
}
/**
* 乘法/除法
* @param first 第一个数
* @param second 第二个数
* @param flg true乘法/false除法
* @returns {number|string|number}
*/
function multipleOrDivision(first, second, flg) {
let sec = second;
if (!flg && second[0] == 0) {
return "Inf";
} else if (!flg) {
// 让负号始终保持在分母上
second[0] = -1 * second[0];
second[1] = -1 * second[1];
sec = second.reverse();
}
return simplify(first[0] * sec[0], first[1] * sec[1]);
}
/**
* 求最小公倍数
* @param first 第一个数
* @param second 第二个数
* @returns {number}
*/
function getMinMultiple(first, second) {
let a = first;
let b = second;
let c = first * second;
if (a < b) {
let r = a;
a = b;
b = r;
}
while (true) {
let r = a % b;
if (r === 0) {
return c / b;
} else {
a = b;
b = r;
}
}
}
/**
* 数据简化
* @param molecule 分子
* @param denominator 分母
*/
function simplify(molecule, denominator) {
if (molecule == 0) {
// 分子是0,那么数据就是0
return 0;
} else if (molecule < denominator) {
// 如果分子小于分母,需要判断是否可以约分
// 这种情况可能是负数
if (molecule < 0) {
let res1 = simplify(molecule * -1, denominator);
return `(-${res1})`;
} else {
return getMaxDivisor(molecule, denominator);
}
} else {
// 整数部分
let integer = Math.floor(molecule / denominator);
// 小数部分分子
let decimals = molecule % denominator;
if (decimals === 0) {
// 整数
return integer;
} else {
// 这里同样需要判断是否可以约分
let res2 = getMaxDivisor(decimals, denominator);
return `${integer} ${res2}`;
}
}
}
/**
* 辗转相除法约分
* @param first 分子
* @param second 分母
* @returns {string|number}
*/
function getMaxDivisor(first, second) {
let mid1 = first;
let mid2 = second;
let mid3 = 0;
for (let i = 0; i < i + 1; i++) {
mid3 = mid1 % mid2;
if (mid3 === 0) {
break;
} else {
mid1 = mid2;
mid2 = mid3;
}
}
if (mid2 === second) {
return first / mid2;
} else {
return `${first / mid2}/${second / mid2}`;
}
}
抢到音乐节票啦!!!!!我要去见十个勤天啦!!!!!!