How to improve layout of long multiplication and add decimal arithmetic to arithmetic alogorithms

I don’t want to sound petty, but some proper attribution would be nice. The addition algorithm was my creation: Discord

That said, I’m glad you posted this here, since on Discord nobody would have ever seen it again.


Just to be safe, I’ll post it here again so that there is no doubt anyone can reuse this code according to the CC-BY 4.0 license:

the addition algorithm
#set text(3em)

// convert a number to a string, split it into characters, and convert it back into digits
#let digits(x) = str(x).clusters().map(int)

#let summation(..summands) = {
  assert.eq(summands.named(), (:))
  // represent each summand as an array, least significant digit first
  let summands = summands.pos().map(x => digits(x).rev())
  let len = calc.max(..summands.map(array.len))

  // do the summation, digit by digit
  let columns = ()
  let carry = 0
  for i in range(len) {
    // get all the digits
    let summands = summands.map(x => x.at(i, default: none))
    // calculate sum, split into ones and tens
    let sum = summands.sum() + carry
    let (sum, new-carry) = (calc.rem(sum, 10), int(sum/10))
    // save the result, always prepending so that the most significant
    // digits end up left
    columns.insert(0, (
      summands: summands,
      sum: sum,
      carry: carry,
    ))
    carry = new-carry
  }
  // add a final column if there's a carry
  if carry != 0 {
    columns.insert(0, (
      summands: (none,) * summands.len(),
      sum: carry,
      carry: 0,
    ))
  }
  // add a dummy column for the addition sign
  columns.insert(0, none)

  grid(
    columns: columns.len(),
    inset: 0.1em,
    // go through all summands
    ..range(summands.len()).map(r => {
      // go through all columns
      columns.enumerate().map(((c, col)) => {
        if col == none {
          // this is the first column
          if r == summands.len() - 1 [+]
          else []
        } else {
          // this is a regular column
          if r == 0 and col.carry != 0 {
            // first line: put the carry
            place(dx: -0.15em, dy: -0.1em, text(0.4em)[#col.carry])
          }
          // put the digit
          [#col.summands.at(r)]
        }
      })
    }).flatten(),
    grid.hline(),
    // sum
    ..columns.enumerate().map(((c, col)) => {
      if col == none []
      else [#col.sum]
    }),
  )
}

#summation(744, 2480)
8 Likes