Подтвердить что ты не робот

TimeSpan FromMilliseconds странная реализация?

Недавно я столкнулся с каким-то странным поведением в реализации .net timespan.

        TimeSpan test = TimeSpan.FromMilliseconds(0.5);
        double ms = test.TotalMilliseconds; // Returns 0

FromMilliseconds принимает двойной параметр. Однако, кажется, значение округлено внутри.

Если я создаю новый временной интервал с 5000 тиками (.5 мс), значение TotalMilliseconds будет правильным.

Взгляд на реализацию TimeSpan в рефлекторе показывает, что вход на самом деле отличен до длинного.

Почему Microsoft разработала метод FromMilliseconds для принятия двойного параметра вместо длинного (поскольку двойное значение бесполезно с учетом этой реализации)?

4b9b3361

Ответ 1

Первое соображение заключается в том, чтобы задаться вопросом, почему они выбрали значение double как возвращаемое значение. Использование долгого времени было бы очевидным выбором. Хотя уже существует отличное свойство, которое долгое время, Ticks недвусмысленно с единицей в 100 наносекунд. Но они выбрали double, возможно, с намерением вернуть дробное значение.

Это создало новую проблему, которая, возможно, была обнаружена позже. Двойник может хранить только 15 значащих цифр. TimeSpan может хранить 10 000 лет. Очень желательно конвертировать из TimeSpan в миллисекунды, затем вернуться к TimeSpan и получить то же значение.

Это невозможно с двойным. Выполнение математики: 10 000 лет составляет примерно 10000 х 365,4 х 24 х 3600 х 1000 = 315,705,600,000,000 миллисекунд. Отсчитайте 15 цифр, лучше всего сделать двойной, и вы получите ровно одну миллисекунду как самый маленький блок, который все еще можно сохранить без ошибки округления. Любые дополнительные цифры будут случайным шумом.

Застыв между камнем и жестким местом, дизайнерам (тестерам?) пришлось выбирать между округлением значения при переходе с TimeSpan на миллисекунды. Или сделать это позже при переходе от миллисекунд к TimeSpan. Они решили сделать это рано, мужественное решение.

Решите свою проблему, используя свойство Ticks и умножая на 1E-4, чтобы получить миллисекунды.

Ответ 2

Это по дизайну, очевидно. Документация говорит так:

Параметр значения преобразуется в тиков, и это количество тиков используется для инициализации нового TimeSpan. Следовательно, значение будет только с точностью до ближайшего миллисекунды.

Ответ 3

Принятие двойника - логический дизайн. Вы можете иметь доли миллисекунд.

Что происходит внутри - это проект внедрения. Даже если все текущие реализации (CLI) округляют его сначала, что не обязательно будет иметь место в будущем.

Ответ 4

Проблема с вашим кодом на самом деле является первой строкой, где вы вызываете FromMilliseconds. Как отмечалось ранее, в документации в документации указано следующее:

Параметр значения преобразуется в тики, и это число тиков используется для инициализации нового TimeSpan. Поэтому значение будет считаться точным только с точностью до ближайшей миллисекунды.

В действительности это утверждение не является ни правильным, ни логически обоснованным. В обратном порядке:

  • Клещи определяются как "100 наносекунд". По этому определению документация должна быть написана как:

    Следовательно, значение будет считаться точным с точностью до ближайшего миллисекунды или одной десятимиллионной секунды.

  • Из-за ошибки или недосмотра параметр значения не преобразуется непосредственно в тики до инициализации нового экземпляра TimeSpan. Это можно увидеть в исходном источнике для TimeSpan, где значение millis округлено до его преобразования в тики, а не после. Если бы максимальная точность была сохранена, эта строка кода должна была бы выглядеть следующим образом (и настройка на 0,5 миллисекунды 3 строки ранее была бы удалена):

    return new TimeSpan((long)(millis * TicksPerMillisecond));
    

Резюме:

Документация для различных TimeSpan.From*, за исключением FromTicks, должна быть обновлена, чтобы указать, что аргумент округлен до ближайшей миллисекунды (без ссылки на тики).

Ответ 5

Или вы могли бы сделать:

double x = 0.4;

TimeSpan t = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * x)); // where x can be a double
double ms = t.TotalMilliseconds; //return 0.4

- сарказм

TimeSpan преобразует двойной миллисекунды в тики, поэтому " OBVIOUSLY" вы можете иметь TimeSpan с гранулярностью менее 1 мс.

-/сарказм

- это совсем не очевидно... почему это не делается внутри метода .FromMilliseconds вне меня.