2012-03-14 2 views
12

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

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

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


Edit 1

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

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

(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 

Edit 2

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

+0

Возможно, проблема связана с типом данных, поскольку AddDays занимает двойное. Похоже, разница должна быть намного меньше 15 секунд. Ознакомьтесь с http://en.wikipedia.org/wiki/Double_precision, чтобы увидеть, как он просто аппроксимирует значения. –

+1

Вы пытались изменить порядок вызовов метода, чтобы узнать, получаете ли вы тот же результат? Вероятно, это не изменит ситуацию, но мне любопытно. –

+3

Я не смог воспроизвести это (на компиляторе C# 4). Какая у вас среда? – SWeko

ответ

3

Это результат того, что 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 принимает целое число и не использует арифметику с плавающей запятой. Таким образом, результат является точным.

4

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

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

(клещ внутреннее "квант" от времени DateTime. Это довольно короткий. Это one ten-millionth of a second

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

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

+1

То же самое для меня ... –

+0

В моем проекте это всегда так (не так), но когда я создаю новый проект, он работает как ожидалось – user1269009

+0

@ user1269009 Итак, вы взяли две строки, которые я написал, скопировали в нее VERBATIM в вашем старый проект и смотрел тики? – xanatos