2018年11月18日 星期日

C++ 學習筆記:chrono - Part 1 duration

Hello World Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <chrono>
#include <ratio>
#include <iostream>
#include <iomanip>

template <typename T>
class TD;

template <typename _Value, typename _Fraction>
std::ostream& operator << (std::ostream& os, const std::chrono::duration<_Value, _Fraction>& dur)
{
    os << "[" << dur.count() << " of " << _Fraction::num << "/" << _Fraction::den << " sec]";
    return os;
}

int main()
{
    /* Basic Representation */
    std::chrono::duration<int> twentySec(20);  // value: 20, fraction: 1 sec (default)
    std::chrono::duration<double, std::ratio<60>> halfMin(0.5); // value: 0.5, fraction: 60 sec
    std::chrono::duration<long, std::milli> oneMs(1);  // value: 1, fraction: 1 milli sec

    /* Use Helper Class */
    std::chrono::seconds twentySec2(20);
    std::chrono::hours oneDay(24);
    std::chrono::microseconds oneMs2(1);
    //std::chrono::minutes halfMin2(0.5);// compile error, the duration type is int

    /* Arithmetic */
    std::chrono::seconds d1(42);
    std::chrono::milliseconds d2(10);
    auto diff = d1 - d2;
    std::cout << diff.count() << std::endl; // 41990 (of 1/1000 sec)

    std::chrono::duration<int, std::ratio<1, 3>> d3(1);
    std::chrono::duration<int, std::ratio<1, 5>> d4(1);
    auto add = d3 + d4;
    std::cout << add.count() << std::endl; // 8 (of 1/15 sec)
    std::cout << std::boolalpha << (d3 < d4) << std::endl;// false

    /* Arithmetic Return Type */
    //TD<decltype(diff)> x;// compiler deduce: TD<std::chrono::duration<__int64,std::milli>>
    //TD<decltype(add)> x;// compiler deduce: TD<std::chrono::duration<int,std::ratio<0x01,0x0f>>>
    //TD<decltype(twentySec2 - oneDay)> x;// compiler deduce: TD<std::chrono::duration<__int64,std::ratio<0x01,0x01>>>
    //TD<decltype(twentySec2 - oneMs2)> x;// compiler deduce: TD<std::chrono::duration<__int64,std::micro>>

    /* Arithmetic and Conversion */
    std::chrono::milliseconds ms(0);    // undefined value without (0)
    ms += twentySec2 + oneDay;
    --ms;
    ms *= 2;
    std::cout << ms.count() << " ms" << std::endl;//172839998 ms

    std::chrono::nanoseconds ns(ms);
    std::cout << ns.count() << " ns" << std::endl;// 172839998000000 ns

    /* Static Operations */
    auto zeroMS = std::chrono::milliseconds::zero();// duration with zero value
    auto maxMS = std::chrono::milliseconds::max();// duration with max value
    auto minMS = std::chrono::milliseconds::min();// duration with min value

    using TypeMsValue = std::chrono::milliseconds::rep;
    using TypeMsFraction = std::chrono::milliseconds::period;

    std::cout << twentySec << std::endl;    // use overloaded operator <<
    std::cout << d3 << std::endl;           // use overloaded operator <<

    /* Explicit Conversion */
    // example 1: convert to different fraction
    std::chrono::seconds sec(55);
    //std::chrono::minutes m1 = sec;  // compile-time error
    std::chrono::minutes m1 = std::chrono::duration_cast<std::chrono::minutes>(sec);
    std::cout << m1 << std::endl;   // value 0 due to information lost

    // example 2: conver to different value type, double to long long
    halfMin;// type: std::chrono::duration<double, std::ratio<60>>
    //std::chrono::seconds s1 = halfMin; // compile-time error
    std::chrono::seconds s1 = std::chrono::duration_cast<std::chrono::seconds>(halfMin);
    std::cout << s1 << std::endl;   // [30 of 1/1 sec]

    // example 3: segment into different units
    ms = std::chrono::milliseconds(7255042);
    std::chrono::hours hh = std::chrono::duration_cast<std::chrono::hours>(ms);
    std::chrono::minutes mm = std::chrono::duration_cast<std::chrono::minutes>(ms % std::chrono::hours(1));
    std::chrono::seconds ss = std::chrono::duration_cast<std::chrono::seconds>(ms % std::chrono::minutes(1));
    std::chrono::milliseconds msec = std::chrono::duration_cast<std::chrono::milliseconds>(ms % std::chrono::seconds(1));

    std::cout << "raw: " << hh << "::" << mm <<  "::" << ss << "::" << msec << std::endl;
    std::cout << "     " << std::setfill('0') << std::setw(2) << hh.count() << "::"
                                              << std::setw(2) << mm.count() << "::"
                                              << std::setw(2) << ss.count() << "::"
                                              << std::setw(2) << msec.count() << std::endl;
}


chrono

chrono library 是一個可以提供時間與日期且精準度中性的 C++11 函式庫
主要成分:
  1. duration: 在一個時間單位下的數量。例如,3 個 分鐘(minute)  表示 3 分鐘、3 個 0.5秒(0.5 seconds) 表示 1.5 秒
  2. timepoint: 一個起始時間(epoch) 與一個 duration 的組合。例如,千禧年午夜,可表示成 自從 1970 年 1 月 1 日起 1262300400 秒
  3. clock: 用來定義 epoch,不同的 clock 有不同的 epoch

Duration

  • 為 value 與 fraction 的組合,其中:
    • value
      • 表示次數
      • duration 的第一個 template argument 為此次數的型別
    • fraction
      • 表示以秒為基準的單位
      • 常用 ratio 來表示
  • 常用的 helper type 可參考此 Link
    • 注意:value 的 type 僅支援 signed integer
  • 若使用 default ctor 建構 duration,(即不傳入任何參數),其值是 undefined


Duration 的運算

  • 兩個 duration 運算後,以秒為基準的單位可能會改變,即 fraction 部分可能會不同
    • 回傳型別是 common_type 的 SPECIALIZATIONS,為一個 duraiton,其中:
      • value 定義為兩個 duration value 的 common_type
      • fraction 定義為 ratio<兩者最大公因數, 兩者最小公倍數>
  • 不同 Duration 間轉換
    • implicit type conversion
      • 一個 duration 也可透過 ctor 或 assignment 轉成另一個單位的 duration,只要有支援 implicit type conversion (僅限於大單位轉小單位,即變得更精準的情況)
    • duration_cast
      • 若要從小單位轉大單位,即有機會造成資訊流失情況下,需要用 duration_cast,例如 42010 ms 轉成 42 s
Note:
使用 Visual Studio 2013 測試上面的 code,發現 84 到 86 行不 work,應該是 VS 的 lib 實作有問題,回傳型別方面的問題,這邊就不深入研究此錯誤了。另一方面,使用 g++ 就完全正常。

Reference:

  1. The C++ Standard Library: A Tutorial and Reference, Second Edition
  2. Visual Studio 2013

沒有留言:

張貼留言