Fraction.fromDouble constructor

Fraction.fromDouble(
  1. double value, {
  2. double precision = 1.0e-12,
})

Tries to give a fractional representation of a double according with the given precision. This implementation takes inspiration from the continued fraction algorithm.

 Fraction.fromDouble(3.8) // represented as 19/5

Note that irrational numbers can not be represented as fractions. If you try to use this method on π (3.1415...) for example, you won't get a valid result:

 Fraction.fromDouble(math.pi)

The above code doesn't throw. It returns a Fraction object because the algorithm only considers the first 10 decimal digits (since precision is set to 1.0e-10).

 Fraction.fromDouble(math.pi, precision: 1.0e-20)

This example will return another different value because it considers the first 20 digits. It's still not a fractional representation of π because irrational numbers cannot be expressed as fractions.

You should only use this method with rational numbers.

Implementation

factory Fraction.fromDouble(double value, {double precision = 1.0e-12}) {
  _checkValue(value);
  _checkValue(precision);

  // Storing the sign
  final abs = value.abs();
  final mul = (value >= 0) ? 1 : -1;
  final x = abs;

  // How many digits is the algorithm going to consider
  final limit = precision;
  var h1 = 1;
  var h2 = 0;
  var k1 = 0;
  var k2 = 1;
  var y = abs;

  do {
    final a = y.floor();
    var aux = h1;
    h1 = a * h1 + h2;
    h2 = aux;
    aux = k1;
    k1 = a * k1 + k2;
    k2 = aux;
    y = 1 / (y - a);
  } while ((x - h1 / k1).abs() > x * limit);

  // Assigning the computed values
  return Fraction(mul * h1, k1);
}