Страница 1 из 2

TDateTime: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 28 дек 2007, 14:21
BBB
Код на Delphi:

Код: Выделить всё

uses DateUtils;

var datetime_1, datetime_2 : TDateTime; 

 datetime_1 := EncodeDateTime(2007, 12, 12, 14, 56, 06, 0);
 datetime_2 := EncodeDateTime(2007, 12, 12, 14, 56, 10, 0);
   // Здесь результат будет: 4
 ShowMessage (IntToStr (SecondsBetween (datetime_1, datetime_2)));
  
 datetime_1 := EncodeDateTime(2007, 12, 12, 14, 53, 06, 0);
 datetime_2 := EncodeDateTime(2007, 12, 12, 14, 53, 10, 0);
   // А здесь результат будет: 3
 ShowMessage (IntToStr (SecondsBetween (datetime_1, datetime_2)));
Т.е. при вычислении разности двух моментов времени в секундах где-то происходит отбрасывание значащих цифр (а не округление, как мы увидим ниже). Ведь время в тиее данных TDateTime хранится как дробная часть числа. Причем, похоже, если число минут не меньше (10*n + 5), то результат получается верным, если меньше, то на единицу меньше. (Хотя глобальных экспериментов не проводил, м/б условие еще более тонкое)

Если же в предыдущем примере вычислить разность в миллисекундах,
то получим результаты 4000 и 3999.

Отсюда и можно следать предположение, что [в какой-то момент - ?] при вычислении секунд "лишние" цифры отбрасываются, а не округляются!

Т.е. более точная разность в секундах между двумя моментами времени получится при использовании:

round (SecondsMilliBetween (datetime_1, datetime_2) / 1000);

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 28 дек 2007, 16:21
BBB
Дейттвительно, исходный текст ф-и SecondsBetween выглядит как:

Код: Выделить всё

function SecondsBetween(const ANow, AThen: TDateTime): Int64;
begin
  Result := Trunc(SecondSpan(ANow, AThen));
end;
Так что, вместо
round (SecondsMilliBetween (datetime_1, datetime_2) / 1000);
проще сделать:
Round(SecondSpan(datetime_1, datetime_2));

Но тем не менее.
Можно сказать, что программист - это пользователь программы "компилятор Delphi".
И с точки зрения ЗДРАВОГО СМЫСЛА и с точки зрения пользователя, длина интервала
от 14:53:06 до 14:53:10 В ТОЧНОСТИ РАВНА длине интервала от 14:56:06 до 14:56:10.
Тем не менее программа "компилятор Delphi" утверждает, что длины этих
интервалов различны! Странная логика у этой программы :)

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 28 дек 2007, 16:34
somewhere
&quot писал(а):Result := Trunc(SecondSpan(ANow, AThen));
Как то все закручено, хрен знает... как в мыльной опере, по идее разница в секундах это всеже
trunc((Athen - ANow)*86400) - т.е. количество полных секунд, там не надо округлять

.

Добавлено: 28 дек 2007, 17:41
BBB
somewhere писал(а):Как то все закручено, хрен знает... как в мыльной опере, по идее разница в секундах это всеже
trunc((Athen - ANow)*86400) - т.е. количество полных секунд, там не надо округлять
Ну так когда они запихивают время в дробную часть, вот, видимо, тут-то у них погрешность и появляется. А потом аукается.
Вообще-то, раз уж они предоставляют класс, то меня, как пользователя этого класса, по идее, не должен волновать их способ хренения информации. Т.е. их класс для меня - черный ящик. Но на выходе, воспользовавшись функцями, обрабатывающими этот класс, я в данном сулчае получаю результат, противоречащий здравому смыслу.

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 28 дек 2007, 18:45
somewhere
BBB, проверил, все сходиться, не стал брать точный номер дня, но взял какой то в этом году. Обьявил все переменные как Double, вот что получилось

a := 53766 / 86400 + 39426; //14:56:06
b := 53770 / 86400 + 39426; //14:56:10
c := 53586 / 86400 + 39426; //14:53:06
d := 53590 / 86400 + 39426; //14:53:10

b-a = 0,000046296299842652, в секундах *86400 = 4,0000003064051328
d-c = 0,000046296292566694, в секундах *86400 = 3,9999996777623616
Результат на лицо, нетрудно догаться что будет после Trunc ;)

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 29 дек 2007, 10:38
BBB
somewhere,
Кстати, делят они не на 86400, а на 86400000, так как там (в TDateTime) и миллисекунды хранятся. Оно, конечно, вроде, принципиально ничего не меняет, т.к. предварительно часы, минуты и секунды на лишнюю же 1000 и множатся. Только появляется больше значащих цифр после запятой, если кол-во миллисекунд не нулевое.

Код: Выделить всё

const
  HoursPerDay   = 24;
  MinsPerDay    = HoursPerDay * 60;
  SecsPerDay    = MinsPerDay * 60;
  MSecsPerDay   = SecsPerDay * 1000;

function TryEncodeTime(Hour, Min, Sec, MSec: Word; out Time: TDateTime): Boolean;
begin
  Result := False;
  if (Hour < 24) and (Min < 60) and (Sec < 60) and (MSec < 1000) then
  begin
    Time := (Hour * 3600000 + Min * 60000 + Sec * 1000 + MSec) / MSecsPerDay;
    Result := True;
  end;
end;

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 29 дек 2007, 21:10
Duncon
Ребят, вы о чем? Время помоему везде храниться в значениях с плавающей точкой (типа Double)..

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 01 янв 2008, 15:52
somewhere
&quot писал(а):Ребят, вы о чем? Время помоему везде храниться в значениях с плавающей точкой (типа Double)..
Ну так мы об этом и говорим, что точности не хватает...

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 01 янв 2008, 16:05
Duncon
Точность понятие относительная, сам подумай про скорость изменения времени в какой-нить +7 степени.. Думается скорее не хватает количества тиков проца за секунду для таких исчислений, вот и все любовь..

Re: Какая прелесть! или Еще немного о теории относительности.

Добавлено: 02 янв 2008, 12:08
somewhere
Нет, не в этом дело. Тут проблема в самом формате представления даты/времени как в числе типа Double, где 1 день равен единице, а время фактически является дробной частью числа. Потеря точности дробной части начинает возникать при увеличении целой части - об этом гласит формат представления вещественных чисел в двоичном виде. Тики процессора с этим не связаны никак. В проце начиная с P166 реализован целочисленный 64 битный счетчик тиков (time stamp counter) который увеличивается на единицу каждый тактовый цикл поступающий от генератора. Этот счетчик работает независимо от выполняемых комманд. Он обнуляется только когда выполняется аппаратный сброс процессора, даже при тактовой частоте 3ГГц 64 бит счетчика хватит на 200 лет.