2

I'm dealing with physical entities, such as time, speed and distance, and performing simple math, such as distance = time * speed, etc. Speed and Distance are double values rounded to 8th digit, and for Time values a .NET TimeSpan is used. Since TimeSpan rounds to a closest millisecond, I'm getting rounding errors, so I need to write custom rounding method that rounds all calculations to the closest millisecond. For example (rounding to 8th digit is omitted for simplicity):

  static void Main(string[] args) {
     var dist = 1.123451;
     var speed = 1.123452;

     var timeA = TimeSpan.FromHours(dist / speed);
     var timeB = timeA + TimeSpan.FromMilliseconds(1);

     var distA = _round(timeA.TotalHours * speed);
     var distB = _round(timeB.TotalHours * speed);

     var timeA1 = TimeSpan.FromHours(distA / speed);
     var timeB1 = TimeSpan.FromHours(distB / speed);

     // a correct implementation should give both the following vars true
     var isDistributive = distA == dist;
     var isPrecise = (timeB1 - timeA1) == TimeSpan.FromMilliseconds(1);
  }

  public static double _round(double d) {
     // Q: what should be here?
  }
  • Using Math.Round(d, 6) is distributive, but loses precision (precise up to ~4 msec)
  • Using Math.Round(d, 7) is precise to a single msec, but not distributive (distA above will be 1.1234511 != 1.123451)
  • Using the following (round to closest msec) seems to be correct, but the rounding code itself introduces its own double precision errors:

      public static double _round(double d) {
        var pre = 3600000.0;
        return Math.Round(d * pre) / pre;
      }
    

Thanks, Boris.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Borka
  • 2,169
  • 3
  • 20
  • 26

2 Answers2

2

Jon Skeet is likewise unhappy with .Net time calculations, and working on a project called noda-time, which I believe might solve this problem. I don't know if the project is far enough along to be of use to you yet, but it is worth checking.

Edit: Shamelessly invoking the name of JS in the hopes of getting people to use and improve libraries rather than (unnecessarily) reinventing the wheel.

Community
  • 1
  • 1
WillfulWizard
  • 5,340
  • 2
  • 19
  • 15
0

Try using decimal instead of double types. They are more precise (28 digits precision) and should fit your need without having to implement the custom round function.

Carvellis
  • 3,992
  • 2
  • 34
  • 66
  • My problem is not losing double precision, my problem is losing precision in TimeSpan.FromHours – Borka Jul 26 '10 at 18:02