divide method

FpvType divide(
  1. FloatingPointValue a,
  2. FloatingPointValue b, {
  3. FloatingPointRoundingMode roundingMode = FloatingPointRoundingMode.roundNearestEven,
})

Divides a by b exactly (to sufficient precision) and rounds once into this format.

b must be nonzero: callers are expected to handle infinity and zero-divisor special cases before calling this (as FloatingPointValue.operator / does). NaN operands are propagated correctly.

Implementation

FpvType divide(FloatingPointValue a, FloatingPointValue b,
    {FloatingPointRoundingMode roundingMode =
        FloatingPointRoundingMode.roundNearestEven}) {
  if (a.isNaN | b.isNaN) {
    return _propagateNaN(a, b);
  }
  final negative = a.sign.toBool() != b.sign.toBool();

  final aExact = _decodeFinite(a);
  final bExact = _decodeFinite(b);
  if (aExact.significand == BigInt.zero) {
    return _zero(negative);
  }

  // Compute the quotient's significand to at least `guardBits` bits more
  // precision than the target format needs, by left-shifting the
  // dividend before doing exact BigInt integer division. Shifting left
  // (never right) means no dividend precision is ever silently
  // discarded. Any nonzero remainder from the integer division is folded
  // into the quotient's LSB as a sticky bit -- a standard technique so
  // that information about further (unrepresented) nonzero low-order
  // bits isn't lost for tie-breaking during later rounding.
  final fractionWidth = mantissaWidth - (explicitJBit ? 1 : 0);
  final guardBits = fractionWidth + 4;
  final shiftAmount = max(
      0,
      bExact.significand.bitLength +
          guardBits -
          aExact.significand.bitLength);
  final shiftedDividend = aExact.significand << shiftAmount;
  var quotient = shiftedDividend ~/ bExact.significand;
  final remainder = shiftedDividend.remainder(bExact.significand);
  if (remainder != BigInt.zero) {
    quotient |= BigInt.one;
  }

  return _quantize((
    significand: quotient,
    exponent: aExact.exponent - bExact.exponent - shiftAmount,
  ), negative: negative, roundingMode: roundingMode);
}