withScale method

Decimal withScale(
  1. int scale,
  2. RoundingMode mode
)

Convert to Decimal with specified scale and rounding mode

Implementation

Decimal withScale(int scale, RoundingMode mode) {
  if (_scale == scale) {
    return this;
  }

  if (_scale < scale) {
    final factor = pow10(scale - _scale);
    return Decimal(_value * factor, scale);
  }

  final factor = pow10(_scale - scale);
  var rounded = _value ~/ factor;

  final remainder = _value.remainder(factor);
  final half = factor ~/ BigInt.two;
  final isNegative = _value < BigInt.zero;
  final absRemainder = remainder.abs();

  switch (mode) {
    case RoundingMode.up:
      if (remainder != BigInt.zero) {
        rounded = isNegative ? rounded - BigInt.one : rounded + BigInt.one;
      }
      break;
    case RoundingMode.down:
      break;
    case RoundingMode.ceiling:
      if (remainder != BigInt.zero && !isNegative) {
        rounded = rounded + BigInt.one;
      }
      break;
    case RoundingMode.floor:
      if (remainder != BigInt.zero && isNegative) {
        rounded = rounded - BigInt.one;
      }
      break;
    case RoundingMode.halfUp:
      if (absRemainder >= half) {
        rounded = isNegative ? rounded - BigInt.one : rounded + BigInt.one;
      }
      break;
    case RoundingMode.halfDown:
      if (absRemainder > half) {
        rounded = isNegative ? rounded - BigInt.one : rounded + BigInt.one;
      }
      break;
    case RoundingMode.halfEven:
      if (absRemainder > half) {
        rounded = isNegative ? rounded - BigInt.one : rounded + BigInt.one;
      } else if (absRemainder == half) {
        if (rounded.isOdd) {
          rounded = isNegative ? rounded - BigInt.one : rounded + BigInt.one;
        }
      }
      break;
    case RoundingMode.unnecessary:
      if (remainder != BigInt.zero) {
        throw ArgumentError(
          'Rounding necessary: value cannot be represented exactly with scale $scale',
        );
      }
      break;
  }

  return Decimal(rounded, scale);
}