I am using a LinearProgressIndicator to visually display a countdown of time and trigger a function at certain intervals. I am doing this by updating the LinearProgressIndicator's value prop using a state variable _progress that gets decremented by 0.01 each 100 milliseconds. When I set conditions that were based on two decimal points, or even 0 if (_progress == 0.75), I discovered that the conditions were being skipped because the value of _progress was quickly becoming a much larger fraction that would not match my condition (e.g. 0.7502987777777). I assume this is an inherent issue of working with doubles, but my question then becomes, what is the best way to deal with this if you want to trigger actions based on the value of _progress? My approach is to broaden the conditions - for example if (_progress > 0.75 && _progress < 0.76).

Any tips/advice would be appreciated. Thanks.


Solution 1: jamesdlin

When dealing with floating-point values, you often cannot depend on strict equality. Instead you should check if the floating-point value you have is within a certain tolerance of the desired value. One approach:

bool closeTo(double value1, double value2, [double epsilon = 0.001]) =>
  (value1 - value2).abs() <= epsilon;

if (closeTo(_progress, 0.75)) {
  // Do something.
}

(package:matcher has a similar closeTo function for matching values in tests.)

Arguably, since floating-point values are floating, your tolerance should depend on the magnitude of the values.

In your case, you alternatively should strongly consider avoiding floating-point values for internal state: use fixed-point values by multiplying everything by 100 and using ints instead. That is, let _progress be an int, decrement it by 1 every 100 ms, and then you can compare against 75 or other values directly and exactly. This additionally would have the advantage of not accumulating floating-point error when you repeatedly decrement _progress. If you need to present _progress to the user or pass it to LinearProgressIndicator, use _progress / 100 instead.