1

I have this function

void prtduration(const FILETIME *ft_start, const FILETIME *ft_end) 
{
    double duration = (ft_end->dwHighDateTime - ft_start->dwHighDateTime) *
        (7 * 60 + 9 + 496e-3)
        + (ft_end->dwLowDateTime - ft_start->dwLowDateTime) / 1e7;
    printf("duration %.1f seconds\n", duration);
    system("pause");
}

Could anybody explain the working of the following part of the code?

(ft_end->dwHighDateTime - ft_start->dwHighDateTime) *
            (7 * 60 + 9 + 496e-3)
            + (ft_end->dwLowDateTime - ft_start->dwLowDateTime) / 1e7;
DevSolar
  • 67,862
  • 21
  • 134
  • 209
Azula
  • 457
  • 2
  • 5
  • 13
  • 2
    If you don't know what it does, then how do you know that it works fine? – eerorika Mar 16 '16 at 07:42
  • It gives me right result. Actually it is lab work from university, example. But I want understand it entirely. – Azula Mar 16 '16 at 08:07
  • You'll need to look at the definition of `FILETIME` to figure that out. It's not in the language standard. ([Looked it up](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284%28v=vs.85%29.aspx), added winapi tag.) – DevSolar Mar 16 '16 at 08:26
  • I know that in dwLowDateTime gets seconds. (ft_end->dwLowDateTime - ft_start->dwLowDateTime) / 1e7 - getting nanoseconds and translating it into seconds. But what means (ft_end->dwHighDateTime - ft_start->dwHighDateTime) * (7 * 60 + 9 + 496e-3)? – Azula Mar 16 '16 at 08:29
  • 2
    It means, "difference between `ft_end`'s high time and `ft_start`'s high time, multiplied with the sum of 429.496". Ladies and gentlemen, here we see the very reason why code comments were invented. Besides, the (linked) documentation for `FILETIME` states, "It is **not recommended that you add and subtract values from the FILETIME structure to obtain relative times**. Instead, you should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure." ;-) – DevSolar Mar 16 '16 at 08:33
  • 2
    FILETIME stores time with a unit of 100 nanoseconds. So the high word unit is pow(2, 32) * 1E-7 seconds = 429.4967296 seconds. Using 7 * 60 + 9 + 496e-3 is a very clumsy way to write that constant, the author apparently cared very little about accuracy on long intervals. – Hans Passant Mar 16 '16 at 08:55

2 Answers2

6

Wow! What an obfuscated piece of code. Let us try to simplify it:

   // Calculate the delta
   FILETIME delta;
   delta.dwHighDateTime = ft_end->dwHighDateTime - ft_start->dwHighDateTime;
   delta.dwLowDateTime = ft_end->dwLowDateTime - ft_start->dwLowDateTime;

   // Convert 100ns units to double seconds.
   double secs = delta.dwHighDateTime * 429.496 + delta.dwLowDateTime/1E7

In actual fact I think this is wrong. It should be:

  double secs = delta.dwHighDateTime * 429.4967296 + delta.dwLowDateTime/1E7

Or even more clearly:

  double secs = (delta.dwHighDateTime * 4294967296. + delta.dwLowDateTime)/10E6

What is happening is that the high time is being multiplied by 2**32 (which converts to 100ns units then divided by 100ns to give seconds.

Note that this is still wrong because the calculation of delta is wrong (in the same way as the original). If the subtraction of the low part underflows, it fails to borrow from the high part. See Microsoft's documentation:

It is not recommended that you add and subtract values from the FILETIME structure to obtain relative times. Instead, you should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure.

Or actually, in this case, just convert the QuadPart to double and divide. So we end up with:

    ULARGE_INTEGER start,end;
    start.LowPart  = ft_start->dwLowDateTime;
    start.HighPart = ft_start->dwHighDateTime;
    end.LowPart = ft_end->dwLowDateTime;
    end.HighPart = ft_end->dwHighDateTime;

    double duration = (end.QuadPart - start.QuadPart)/1E7;

Aside: I bet the reason that the failure to borrow has never been spotted is that the code has never been asked to print a duration of greater than 7 minutes 9 seconds (or if it has, nobody has looked carefully at the result).

0

7 is very approximately frequency when FileTime variable changes its value. Namely, every 7 (+-3 or even more) minutes it increases on 1. Than we multiply it on 60 for getting value in seconds.

9 + 496e-3 - is time is seconds that deals somehow with compilation (from the start of the withdrawal to output in the console) that we are losing.

Really, it is very bad code and we shouldn't write like this.

However it have forced me to learn better about FileTime work.

Thanks everyone for answers, I very appreciate it.

Azula
  • 457
  • 2
  • 5
  • 13