この解答例はChatGPTによって生成されています,正しいかは自己判断で。

BFE.devでのAI解答例 - JavaScript コーディング問題
127. BigDecimal 引き算

解法:

BigInt の場合と同様に、桁上がりの扱いが厄介な問題です。以下の手順に従って実装することができます。

  1. 符号を正規化し、引き算対象の二つの文字列の整数部分と小数部分を抽出する。
  2. 二つの小数部分を桁が合うように調整する。
  3. 二つの整数部分を末尾から順に引き算し、桁上がりを考慮する。
  4. 桁上がりがあった場合、繰り上がりがなくなるまで繰り返す。
  5. 符号、整数部分、小数部分を結合して、最終的な結果を作成する。
  6. 後続ゼロを取り除く。

以下は実装例です。

function subtract(s1, s2) {
  const [sign1, intStr1, decimal1] = normalize(s1)
  const [sign2, intStr2, decimal2] = normalize(s2)

  let intRes = ''
  let decRes = ''

  if (compareAbs(s1, s2) === -1) { // s2 > s1
    [sign1, sign2] = [sign2, sign1]
    ;[intStr1, intStr2] = [intStr2, intStr1]
    ;[decimal1, decimal2] = [decimal2, decimal1]
  }

  let borrow = 0
  let i = intStr1.length - 1
  let j = intStr2.length - 1

  while (i >= 0 || j >= 0) {
    const num1 = i >= 0 ? Number(intStr1[i]) : 0
    const num2 = j >= 0 ? Number(intStr2[j]) : 0

    let diff = num1 - num2 - borrow

    if (diff < 0) {
      diff += 10
      borrow = 1
    } else {
      borrow = 0
    }

    intRes = `${diff}${intRes}`
    i--
    j--
  }

  // Trim leading zeros
  intRes = intRes.replace(/^0+/, '')

  const maxLenDec = Math.max(decimal1.length, decimal2.length)
  let d1 = decimal1.padEnd(maxLenDec, '0')
  let d2 = decimal2.padEnd(maxLenDec, '0')

  for (let i = maxLenDec - 1; i >= 0; i--) {
    let diff = Number(d1[i]) - Number(d2[i]) - borrow

    if (diff < 0) {
      diff += 10
      borrow = 1
    } else {
      borrow = 0
    }

    decRes = `${diff}${decRes}`
  }

  if (borrow === 1) {
    intRes = subtract(`1${intRes}`, '1')
  }

  const resSign = sign1 === '+' ? '' : '-'
  let res = `${intRes}${decRes ? `.${decRes}` : ''}`
  res = trimTrailingZeros(res)

  return resSign + res
}

function normalize(numStr) {
  let sign = ''
  if (numStr[0] === '-' || numStr[0] === '+') {
    sign = numStr[0]
    numStr = numStr.slice(1)
  }
  let [intStr, decimal] = numStr.split('.')
  intStr = intStr || '0'
  decimal = decimal || ''
  return [sign, intStr, decimal]
}

function trimTrailingZeros(numStr) {
  return numStr.replace(/\.?0+$/, '')
}

function compareAbs(numStr1, numStr2) {
  const [_, intStr1, decimal1] = normalize(numStr1)
  const [__, intStr2, decimal2] = normalize(numStr2)

  if (intStr1.length !== intStr2.length) {
    return intStr1.length - intStr2.length
  }

  for (let i = 0; i < intStr1.length; i++) {
    const diff = Number(intStr1[i]) - Number(intStr2[i])
    if (diff !== 0) {
      return diff
    }
  }

  if (decimal1.length !== decimal2.length) {
    return decimal1.length - decimal2.length
  }

  for (let i = 0; i < decimal1.length; i++) {
    const diff = Number(decimal1[i]) - Number(decimal2[i])
    if (diff !== 0) {
      return diff
    }
  }

  return 0
}