roundBigIntByPowerOfTwo function

BigInt roundBigIntByPowerOfTwo(
  1. BigInt value,
  2. int discardedWidth, {
  3. required FloatingPointRoundingMode roundingMode,
})

Divides value by 2^[discardedWidth] using roundingMode.

This operates entirely on BigInt so value-side arithmetic can round without passing through a host floating-point type.

Implementation

BigInt roundBigIntByPowerOfTwo(BigInt value, int discardedWidth,
    {required FloatingPointRoundingMode roundingMode}) {
  if (discardedWidth < 0) {
    throw ArgumentError.value(
        discardedWidth, 'discardedWidth', 'Must be non-negative.');
  }
  if (discardedWidth == 0 || value == BigInt.zero) {
    return value;
  }

  final negative = value.isNegative;
  final magnitude = value.abs();
  final quotient = magnitude >> discardedWidth;
  final remainder = magnitude & ((BigInt.one << discardedWidth) - BigInt.one);
  if (remainder == BigInt.zero) {
    return negative ? -quotient : quotient;
  }

  final increment = switch (roundingMode) {
    FloatingPointRoundingMode.truncate ||
    FloatingPointRoundingMode.roundTowardsZero =>
      false,
    FloatingPointRoundingMode.roundTowardsInfinity => !negative,
    FloatingPointRoundingMode.roundTowardsNegativeInfinity => negative,
    FloatingPointRoundingMode.roundNearestTiesAway =>
      remainder >= (BigInt.one << (discardedWidth - 1)),
    FloatingPointRoundingMode.roundNearestEven =>
      remainder > (BigInt.one << (discardedWidth - 1)) ||
          (remainder == (BigInt.one << (discardedWidth - 1)) && quotient.isOdd),
  };
  final rounded = increment ? quotient + BigInt.one : quotient;
  return negative ? -rounded : rounded;
}