JavaScript PAT乙级题解1034有理数四则运算

本文介绍了如何编写一个程序,处理两个分数形式的有理数,进行加、减、乘、除运算,并确保结果化简为最简形式,包括处理除数为零的情况。作者使用数组存储分子和分母,并运用辗转相除法进行约分和求最小公倍数。
摘要由CSDN通过智能技术生成

本题要求编写程序,计算 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种情况:

  1. 分子为0:整个分数直接为0;
  2. 分子小于分母:此时分子可能为负数,我为了简便直接将分子取反再调用化简函数,return时加上符号就行;再对数据求最大公因数约分;
  3. 分子大于分母:先求整数部分,令分子等于余数,再对分子分母求最大公约数约分。
/**
 * 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}`;
  }
}

抢到音乐节票啦!!!!!我要去见十个勤天啦!!!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值