НОТА: Это, скорее, вопрос о ошибочной математике, а не вопрос
о системном вызове Windows, как описано в вопросе.
Мы работаем с GetSystemTimeAsFileTime()
Позвонил на win32, и, увидев, что я думаю, странные результаты и искал некоторые разъяснения. Из MSDN на структуру FILETIME https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284%28v=vs.85%29.aspx
Содержит 64-битное значение, представляющее число 100 наносекунд
интервалы с 1 января 1601 года (UTC).
Согласно нашему прочтению этого описания, возвращаемое значение является числом 10e-8 интервал секунд. Предполагая, что это правильно, следующая функция должна возвращать системное время в миллисекундах.
DWORD get_milli_time() {
FILETIME f;
::GetSystemTimeAsFileTime(&f);
__int64 nano = (__int64(f.dwHighDateTime) << 32LL)
+ __int64(f.dwLowDateTime);
return DWORD(nano / 10e5);
}
Однако простой юнит-тест показывает, что это неверно, приведенный ниже код выдает «Failed»:
DWORD start = get_milli_time();
::Sleep(5000); // sleep for 5-seconds
DWORD end = get_milli_time();
// test for reasonable sleep variance (4.9 - 5.1 secs)
if ((end - start) < 4900 || (end - start) > 5100) {
printf("Failed\n");
}
Согласно этому посту ТАК
Получение текущего времени (в миллисекундах) от системных часов в Windows?,
правильных результатов можно достичь, изменив наше подразделение на:
return DWORD(nano / 10e3);
Если мы используем это значение, мы получим правильный результат, но я не могу понять, почему.
Мне кажется, что конвертировать из 10e-8 в 10e-3, мы должны разделить на 10e5. Казалось бы, это подтверждается следующими расчетами:
printf("%f\n", log10(10e-3 / 10e-8));
Который возвращает 5 (как я и ожидал).
Но почему-то я не прав — но я буду проклят, если смогу понять, где я ошибся.
Ваша математика действительно ошибочна, как и ваше понимание «рабочего» кода.
Есть 107 100 наносекундных интервалов в секунду, 104 в миллисекунду. В нотации с плавающей точкой это 1.0e4
, 10e3
это странный способ записи 1e4
,
«Правильный» (в смысле наиболее эффективный, но при этом выразительный) код
return DWORD(hundrednano * 1.0e-4);
Других решений пока нет …