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

Ошибка .NET AddDays

Следующие две строки добавляют ту же сумму к одной и той же дате, а часть даты результатов одна и та же, но как-то разница в части времени!

(new DateTime(2000,1,3,18,0,0)).AddDays(4535);   
(new DateTime(2000,1,3,18,0,0)).AddMonths(149);

вы получите разницу в 15 секунд, и с обоими как минимум округлыми до нескольких дней, я не знаю, почему это произошло, но это происходит только с AddDays, но не с AddMonths (даже с добавлением тысяч месяцев)


Изменить 1

Итак, я попытался создать образец проекта, но не повезло. Если я запустил свой основной проект и поместил образцы строк в часы, я получу 2 отдельных значения, если я начну новый старт, проблемы там нет. Проект - 3.5, С#, vs2010, win7hp x64 (proj: x86). Я пытаюсь воспроизвести его также в новом маленьком проекте, я буду писать, если у меня есть.

Это мои результаты в основном проекте (copeid from watches!):

(new DateTime(2000, 1, 3, 18, 0, 0)).AddDays(4535).Ticks    
 634743432153600000 long

(new DateTime(2000, 1, 3, 18, 0, 0)).AddMonths(149).Ticks   
 634743432000000000 long

Изменить 2

Мне удалось еще больше сузить его. У нас есть самодельный компонент, панель, мы рисуем на нем с помощью directx. Если я сделаю видимым = false, чем visible = true, чем ошибка, то перед видимым = true (или show()) вычисление будет правильным. Что в мире может быть там, что результат получает что-то другое формулы, где не используется переменная. Культура не затрагивается в компоненте.

4b9b3361

Ответ 1

Это результат того, что DirectX молчаливо меняет режим вычисления с плавающей запятой CPU, чтобы всегда использовать одинаковую точность. Это иногда делается для производительности: использование одинарной точности может быть немного быстрее, чем использование двойной точности. См. Описание флага FpuPreserve в документации MSDN для перечисления DirectX CreateFlags.

Причина, по которой другие не могут воспроизвести это, заключается в том, что они не выполняют эти вызовы DirectX.

Аргумент AddDays имеет значение double. Это значение умножается на коэффициент масштабирования, чтобы получить время в миллисекундах. Именно этот расчет вызывает ошибку.

Рассмотрим:

double value = 4535;
int scale = 86400000;
long milliseconds = (long) ((value * scale) + ((value >= 0.0) ? 0.5 : -0.5));
long milliseconds2 = (long)((float)(value * scale) + ((value >= 0.0) ? 0.5 : -0.5));
Console.WriteLine(milliseconds2 - milliseconds);

Выражение для milliseconds2 содержит приведение к float, которое имитирует эффект DirectX, который заставляет вычисления с одной точностью. Это напечатает 15360, точно разницу, которую вы найдете.

В отличие от этого, AddMonths принимает целое число и не использует арифметику с плавающей запятой. Таким образом, результат является точным.

Ответ 2

Здесь они дают тот же результат:

var d1 = (new DateTime(2000, 1, 3, 18, 0, 0)).AddDays(4535).Ticks;
var d2 = (new DateTime(2000, 1, 3, 18, 0, 0)).AddMonths(149).Ticks;

d1 == d2 == 634743432000000000

(Tick является внутренним "квантом" времени DateTime.Он довольно короткий. одна десятимиллионная секунда

Я добавлю, что даже Mono (независимая реализация .NET) дает тот же результат http://ideone.com/krySY (Ideone использует моно)

Учитывая более свежие вещи, которые вы написали, это довольно просто: повреждение памяти. Повреждение памяти может делать очень случайные вещи. Вероятно, это один из следующих: -)