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)https://en.wikipedia.org/wiki/Continued_fraction algorithm.

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

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

Fraction.fromDouble(math.pi)

The above returns a fraction because the algorithm considers only 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 pi because irrational numbers cannot be expressed as fractions.

This method is good with rational numbers.

Implementation

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

  // Storing the sign
  final mul = (value >= 0) ? 1 : -1;
  final x = value.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 = value.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.toInt(), k1.toInt());
}