1

I've coded this simple function to round doubles to a custom step size. The normal .round() function retuns an int and can only rounds to the nearest 1. My function returns a double and can round to the nearest 100.0, 5.0, 1.0, 0.1 or 0.23, you get it.

But when I put in certain doubles the result doesn't really work out and is a very tiny fraction off.

I think this has something to do with how computers do floating comma calcualations, but I need an efficient way to get around it.

Run on DartPad

void main() {
  stepround(61.337551616741315, 0.1); // this should be 61.3 but is 61.300000000000004
}

/// rounds a double with given steps/precision
double stepround(double value, double steps) {
  double rounded = (value / steps).round() * steps;
  print(value.toString() + " rounded to the nearest " + steps.toString() + " is " + rounded.toString());
  return rounded;
}

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
1cedsoda
  • 623
  • 4
  • 16
  • See: https://stackoverflow.com/a/60655897/1953515 – julemand101 Jan 09 '21 at 20:04
  • 1
    Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – jamesdlin Jan 09 '21 at 20:23
  • 1
    As for how to get around it: regardless of what base numbers you use, there are always going to be real numbers that can't be exactly represented. You can try using avoiding `double` and instead use [`package:decimal`](https://pub.dev/packages/decimal) which would at least better match your mental model about what numbers are representable. – jamesdlin Jan 09 '21 at 20:45

1 Answers1

0

As mentioned in the comments, the cause of this issue the way that computers deal with floating numbers. Please refer to the links in the comments for further explanation.

However in a nutshell the problem is mostly caused when dividing or multiplying decimals with decimals. Therefore we can create a similar method to the one you created but with a different approach. We we will take the precision to be as an int.

I.e: 0.1 => 10; 0.001 => 1000

double stepround(double value, int place){
   return (value * place).round() / place; 
}

Example

// This will return 61.3
stepround(61.337551616741315, 10);

// This will return 61.34
stepround(61.337551616741315, 100);

// This will return 61.338
stepround(61.337551616741315, 1000);

This method works since the small fraction that is caused by the multiplication is removed by round(). And after that we are doing a division by an integer which doesn't create such a problem.

Mohammad Kurjieh
  • 1,043
  • 7
  • 16