TimeSpan и двойные ошибки округления - PullRequest
2 голосов
/ 26 июля 2010

Я имею дело с физическими объектами, такими как время, скорость и расстояние, и выполняю простую математику, такую ​​как расстояние = время * скорость и т. Д. Скорость и расстояние - это двойные значения, округленные до 8-й цифры, а для значений времени a.NET TimeSpan используется.Поскольку TimeSpan округляется до ближайшей миллисекунды, я получаю ошибки округления, поэтому мне нужно написать собственный метод округления, который округляет все вычисления до ближайшей миллисекунды.Например (округление до 8-й цифры для простоты опущено):

  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?
  }
  • Использование Math.Round (d, 6) является дистрибутивным, но теряет точность (с точностью до ~ 4 мс)
  • Использование Math.Round (d, 7) с точностью до одного мс, но не дистрибутивное (distA выше будет 1.1234511! = 1.123451)
  • Использование следующего (округление до ближайшего мс) кажется правильным, но сам код округления вводит свои собственные ошибки двойной точности:

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

Спасибо, Борис.

Ответы [ 2 ]

2 голосов
/ 27 июля 2010

Джон Скит также недоволен расчетами времени .Net и работает над проектом под названием noda-time , который, как я считаю, может решить эту проблему.Я не знаю, достаточно ли далек проект, чтобы быть полезным для вас, но его стоит проверить.

Редактировать: Бесстыдно вызывать имя JS в надежде заставить людей использовать и улучшатьбиблиотеки, а не (без необходимости) изобретать велосипед.

0 голосов
/ 26 июля 2010

Попробуйте использовать десятичные вместо двойных типов. Они более точные (с точностью до 28 цифр) и должны соответствовать вашим потребностям без необходимости использования пользовательской функции округления.

...