YANFCQ [Yet Another Non-FastCode Question]: TDateTime -> uSec resolution
- From: "Kristofer Skaug" <nospam@xxxxxxxxx>
- Date: Wed, 27 Jul 2005 00:30:13 +0200
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
.
- Follow-Ups:
- Prev by Date: Re: Fastcode - Sponsoring
- Next by Date: Re: NAFCQY [Not A FastCode Question, Yay!]: Int64 DivMod
- Previous by thread: NAFCQY [Not A FastCode Question, Yay!]: Int64 DivMod
- Next by thread: Re: YANFCQ [Yet Another Non-FastCode Question]: TDateTime -> uSec resolution
- Index(es):
Relevant Pages
|