Evert
Evert

Reputation: 99861

Ecmascript bigint, round to even

I'm using the bigint feature from ESNext. When doing division, bigint rounds to 0. Take the following example:

With numbers:

> 3000 / 1578
1.9011406844106464

With bigint:

3000n / 1578n
1n

Instead of rounding to 0, I would like to write a function that can do division but use bankers rounding (round to even).

Example

function divide(a, b) {
  return a/b;
}

I'm just a little stumped how I can write my divide function, and use the remainder to round to even. This is what I tried:

function divide(a, b) {
  let result = a/b;
  // if modulo is over half the divisor
  if ((a % b) * 2n > b) {
     // Add 1 if result is odd
     if (result % 2n === 1n) result++;
  } else {
     // Remove 1 if result is even
     if (result % 2n !== 1n) result--;
  }
  return result;
}

This gives me the right result for divide(3000n, 1578n), but I noticed that this will give me an incorrect result for divide(7n, 2n), which I expected to round to 4n.

Upvotes: 3

Views: 214

Answers (1)

ack_inc
ack_inc

Reputation: 1113

Banker's rounding only affects divisions where the remainder is exactly half the divisor. All other cases get normal rounding.

I think your function should be modified as follows:

function divide(a, b) {

  // Make A and B positive
  const aAbs = a > 0 ? a : -a;
  const bAbs = b > 0 ? b : -b;

  let result = aAbs/bAbs;
  const rem = aAbs % bAbs;
  // if remainder > half divisor, should have rounded up instead of down, so add 1
  if (rem * 2n > bAbs) {
      result ++;
  } else if (rem * 2n === bAbs) {
      // Add 1 if result is odd to get an even return value
      if (result % 2n === 1n) result++;
  }

  if (a > 0 !== b > 0) {
    // Either a XOR b is negative, so the result has to be
    // negative as well.
    return -result;
  } else {
    return result;
  }
}
console.log(divide(3000n, 1578n));
console.log(divide(7n, 2n));
console.log(divide(-7n, 2n));

Upvotes: 4

Related Questions