From: Patrice on
> The only thing where floating points are not 'accurate' is when converting
> numbers from integer, long, and so on into reals or doubles.

IMO the underlying API used doesn't return a single value but a long value
which is then converted to a single value. This is during this conversion to
a floating point value that I believe we could have this approximation...

It makes me think it could be interested to test Timer in parallel with
GetTickCount (http://msdn.microsoft.com/en-us/library/ms724408(VS.85).aspx).
It would allow to see if the same behavior seen with Timer occurs or not
with GetTickCount.

--
Patrice





From: Nobody on
Single was a poor choice for Timer function. Single has accuracy of about 7
digits, so in the middle of the day it would look like 45123.15, so it's
pushing the Single limit.

You could use ABS() function to eliminate negative values, but it's better
to use GetTickCount(). GetTickCount() is unaffected by the user changing the
time by mistake, nor when the system synchronize with an external clock, so
it's more reliable than Timer or DateDiff, both of which are affected by the
time of day. The only issue with GetTickCount() is that it appears negative
after 25 days from last boot, and rolls over to 0 after 49.7 days. To
account for that, you can check if the return value suddenly went negative,
or suddenly went 0. The code below account for all that. The only limitation
is that intervals of more than 49.7 days are not supported, but in most
situations nobody wants that.

Option Explicit

Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Sub Form_Load()
Dim t As Double
Dim i As Long

t = GetTime()
Debug.Print t
For i = 1 To 10000
DoEvents
Next
Debug.Print GetTimeDiff(t)
End Sub

' Returns the time in seconds since Windows has started, or
' since the last rollover to 0 every 49.7 days
Public Function GetTime() As Double
Dim t As Long
Dim d As Double

t = GetTickCount()
If t < 0 Then
' Convert the negative number to 32 bit unsigned
d = 2 ^ 32 - CDbl(t) * -1
Else
d = CDbl(t)
End If

GetTime = Round(d / 1000, 3)

End Function

' Returns the difference in seconds. Maximum period is
' 4294967.295 Seconds or 49.7 days. Compensates for negative
' values or rollover to 0 if it occurred after GetTime() call
Public Function GetTimeDiff(ByRef dStart As Double) As Double
Dim t As Long
Dim d As Double

t = GetTickCount()
If t < 0 Then
' Convert the negative number to 32 bit unsigned
d = 2 ^ 32 - CDbl(t) * -1
Else
d = CDbl(t)
End If

d = d - dStart * 1000
If d < -1 Then ' Avoid very small negative numbers due to precision
' A rollover to 0 has happened, adjust for it
d = d + 2 ^ 32
End If
GetTimeDiff = Round(d / 1000, 3)
End Function