YANFCQ [Yet Another Non-FastCode Question]: TDateTime -> uSec resolution



Dear fellow performance nuts,

lately I've been struggling with some routines to squeeze microsecond
information out of (and into) TDateTime values.
A problem is that I cannot use DecodeTime() because it introduces rounding
errors in determining the Millisecond count, which makes it impossible to
reliably establish the "remainder" i.e. the small sub-millisecond fractional
part "Microseconds in Second". So I have written a routine that circumvents
this problem:

uses SysUtils, DateUtils;
....
const UsecsPerDay = 1000000*SecsPerDay

procedure DecodeTimeUsec(const ATime:TDateTime; out
hh,mm,ss,USecs:LongWord);
var RestTime:Extended; // does this help? not sure
begin
RestTime := Frac(ATime); // chop off Date component, introduces slight
error
// Iterative Trunc()-based division to avoid the cascading rounding errors
// that can be incurred with DecodeTime(), where Msec are rounded.
hh := Trunc( RestTime / OneHour );
RestTime := RestTime - hh*OneHour;
mm := Trunc( RestTime / OneMinute );
RestTime := RestTime - mm*OneMinute;
ss := Trunc( RestTime / OneSecond );
RestTime := RestTime - ss*OneSecond;
USecs := Trunc( RestTime * USecsPerDay);
end; // proc DecodeTimeUsec

This is the "dumbest thing that could possibly work", but I wouldn't be
posting this if I wasn't looking for better performance.
Contrary to all my prejudice against floating point work, the above still
turned out to be twice as fast as an integer-based routine that started by
dividing out Int64 number of microseconds in the day, and then boiling out
Seconds, Minutes and Hours from that

So... to massage further the code I've got above:
One thing I contemplated was a "DivSub" routine in ASM, analogous to integer
DivMod, that would be equivalent to this:

procedure DivSub(const Dividend, Divisor:Extended; out Result:LongWord; out
RemainingFraction:Extended);
begin
Result := Dividend / Divisor;
RemainingFraction := Dividend - Result*Divisor;
end;

But perhaps the best would be to do the whole DecodeTimeUsec in monolithic
ASM...
BTW, does it really make sense to work with Extended here, or could I safely
stick to Double?
Any ideas on either aspect of this multipart question would be muchly
appreciated!

TIA,

--
Kristofer


.



Relevant Pages

  • Re: alarm() - SIGALRM sent too eariy?
    ... I ultimately turns the time into a int holding the number of microseconds, ... I guess you would need to propagate the system setitimer ... Then the originals must be reconstructed with a routine that splits ...
    (comp.lang.perl.misc)
  • Re: Calc time difference between two date/time/zones
    ... between two date/time/zones as shown below. ... routine that can do this easily without having to manually convert ... library routine that does this? ... everything with DecodeTime and DecodeDate to seconds and then back to ...
    (comp.lang.pascal.delphi.misc)