Formatter constructor

Formatter(
  1. List<double> numbers
)

The constructor takes a list of numbers. It is best to provide all the numbers that will be represented alongside each other, or at least a good sample of them.

Implementation

Formatter(List<double> numbers) {
  assert(
      numbers.length >= 2,
      'You should provide at least two numbers '
      'to the formatter. Otherwise it might emit weirdly unspecific'
      'numbers.');

  // The default is the Dart automatic precision.
  var best = _Precision(
    '324.34143423',
    (n) => n.toString(),
  );

  var largestValue = numbers.fold<double>(0, (prev, e) => max(prev, e.abs()));

  final representations = <String>{};
  // For each precision, in order of "vagueness" ...
  for (final precision in _precisions) {
    var cumulativeError = 0.0;
    representations.clear();
    for (final n in numbers) {
      if (!n.isFinite) continue;

      // ... try the precision on each number ...
      final r = precision.formatFunction(n);
      if (representations.contains(r)) break;
      representations.add(r);
      cumulativeError += (n - precision.parseBack(r)).abs();
    }
    // ... discard the ones that accrue too large of an error ...
    if (cumulativeError > 0.05 * largestValue) {
      // (0.05 is an arbitrary constant. It _feels_ weird when the cumulative
      // error is more than 5% of the largest value in the set.)
      continue;
    }
    // ... and see if it results in a set of unique representations.
    if (representations.length == numbers.length) {
      best = precision;
      // No need to continue, we've found our precision.
      break;
    }
  }

  _precision = best;
}