为什么用“std::chrono”进行时差测量时,与“double”类型相比,用“float”类型给出的有效数字更多

Why does time difference measurement with `std::chrono` give more significant digits with `float` type, compared to `double` type?

本文关键字:类型 float 有效数字 double std 时差 测量 为什么 chrono      更新时间:2023-10-16

我使用std::chrono工具测量了几个时间差。我用浮球和双人型都做了测试。结果令人吃惊;双精度类型在第7位之后变为...0000000...9999999,而浮点类型继续显示有效数字。

代码:

std::chrono::steady_clock::time_point Start, End;
std::chrono::duration<float, std::ratio<1, 1>> fDuration;
std::chrono::duration<double, std::ratio<1, 1>> dbDuration;
std::cout.precision(20);
std::cout << std::fixed;
for (DWORD dwSleepTime=0; dwSleepTime<=10000; dwSleepTime+=1000)
{
    Start = std::chrono::steady_clock::now();
    Sleep(dwSleepTime);
    End = std::chrono::steady_clock::now();
    fDuration = std::chrono::duration_cast<std::chrono::duration<float>>(End - Start);
    dbDuration = std::chrono::duration_cast<std::chrono::duration<double>>(End - Start);
    std::cout << "Time passed (float)  = " << fDuration.count()  << std::endl;
    std::cout << "Time passed (double) = " << dbDuration.count() << std::endl << std::endl;
}

其输出:

Time passed (float)  = 0.00000000000000000000
Time passed (double) = 0.00000000000000000000
Time passed (float)  = 1.00005722045898440000
Time passed (double) = 1.00005720000000010000
Time passed (float)  = 2.00011444091796870000
Time passed (double) = 2.00011440000000020000
Time passed (float)  = 3.00017166137695310000
Time passed (double) = 3.00017159999999980000
Time passed (float)  = 4.00022888183593750000
Time passed (double) = 4.00022880000000040000
Time passed (float)  = 5.00028610229492190000
Time passed (double) = 5.00028600000000000000
Time passed (float)  = 6.00034332275390620000
Time passed (double) = 6.00034319999999970000
Time passed (float)  = 7.00040006637573240000
Time passed (double) = 7.00040040000000020000
Time passed (float)  = 8.00045776367187500000
Time passed (double) = 8.00045760000000070000
Time passed (float)  = 9.00051498413085940000
Time passed (double) = 9.00051479999999950000
Time passed (float)  = 10.00057220458984400000
Time passed (double) = 10.00057200000000000000

这种现象背后的原因是什么?在这种特殊情况下,双重类型真的会给出不那么精确的结果吗?


我的系统:
IDE:Visiual Studio 2012
操作系统:Windows 7 x64
CPU:Intel i5 750

double类型精确地表示值。所以,当你打印它们时,你会看到一个非常接近原始值的值。例如,当原始值为1.0000572,并将其转换为double时,结果为1.0000557200000000090511775852064602077007293701171875,因为这是double可以表示的最接近的值。

float类型表示的值不太精确。转换1.0000572时,结果为1.000057220458984375,因为这是一个接近值,因为float可以达到1.0000572。

此外,当您使用Visual Studio软件将这些数字转换为十进制进行打印时,只显示前17位数字,因为Visual Studio会停止显示,并将其余数字打印为零。(应该清楚的是,以这种方式打印它们并不意味着floatdouble对象具有这些值。IEEE-754浮点标准清楚地表明,所表示的确切值是我上面显示的值,即1.0000557220458984375和1.0000557200000000090511775852064602077007293701171875。)。高质量软件根据要求将精确值打印到任意数量的十进制数字。)

您想要了解二进制浮点和精度!float有6位小数精度,double有16位小数精度(我想,但我一直记错了确切的值;请检查std::numeric_limits<T>::digits10)。由于二进制浮点不能准确地表示小数点(只有一些,但很多不是),打印二进制浮点值会导致在离开打印例程执行其想要执行的操作时进行一些舍入。当您要求的数字超过digits10时,四舍五入通常会被推迟,它会打印实际的二进制小数,直到您要求的位数。

在上面描述的情况下,float版本刚刚开始打印实际值(最多可以有std::numeric_limits<T>::digits的有效位)。double版本似乎仍然合理地舍入,尽管要求20位数字已经将其放入了应该/可以/可能显示近似值的区域。当然,这些都与std::chrono无关,只是关于二进制浮点。