建網(wǎng)站有域名和主機seo推廣思路
從現(xiàn)在開始,我們開始介紹 C++ 風(fēng)格的時間處理,在這之前,首先要介紹
std::ratio
。因為 C++ 的chrono
庫中的時間段(duration
)定義離不開std::ratio
,不了解std::ratio
,就很難理解duration
的定義。
1 std::ratio 的基本意義
? std::ratio
是 C++ 11 引入的數(shù)值計算庫的一部分,對應(yīng)的頭文件是 (如果使用時間庫,只要包含頭文件就可以了,這個頭文件內(nèi)部引用了 頭文件)。有資料將其稱之為分?jǐn)?shù),其實它只是提供了比例或比率的概念,并且std::ratio
是個完完全全的泛型庫,它的所有計算都是在編譯期間完成的,其定義如下:
template<std::intmax_t Num, std::intmax_t Denom = 1>
class ratio;
std::intmax_t
表示系統(tǒng)支持的最大位寬的整數(shù),一般 32 位系統(tǒng)中代表的是std::int32_t
,在 64 位的系統(tǒng)上代表的是std::int64_t
。ratio
類還有兩個靜態(tài)成員,一個是ratio::num
,表示約分后的分子,另一個是ratio::den
,表示約分后的分母??匆幌吕哟a就明了了:
assert((std::ratio<24, 32>::num == 3));
assert((std::ratio<24, 32>::den == 4));
//或者:
std::cout << "std::ratio<24, 32>::num = " << std::ratio<24, 32>::num << std::endl;
std::cout << "std::ratio<24, 32>::den = " << std::ratio<24, 32>::den << std::endl;
由于std::ratio
必須在編譯期實例化的,所以std::ratio
類的兩個模板參數(shù)必須都是常量或常量表達(dá)式(constexpr):
int n = 10;
int m = 100;std::ratio<n, m>::num; //ERROR,編譯錯誤const int n = 10;
const int m = 100;
std::ratio<n, m>::num; //OK
? std::ratio
是個類模板,實例化后的std::ratio<24, 32>
就是一個類型,可以用這個類型定義變量(內(nèi)部成員 type
與之等效):
std::ratio<3, 4> a;
//std::ratio<24, 32>::type a; //等效于上一行
assert((a.num == 3)); //注意用了 . 運算符,因為 a 是一個變量了
assert((a.den == 4));
當(dāng)然,也可以用 using
直接使用別名代表一個比率:
using three_fouth = std::ratio<3, 4>;
assert((three_fouth::num == 3)); //注意用了:: 運算符,因為 three_fouthes 是個 std::ratio<3, 4>類型
assert((three_fouth::den == 4));
還有一個很有意思的現(xiàn)象,就是std::ratio<3, 4>
和std::ratio<24, 32>
被視為同種類型,它們的變量可以賦值和交換:
std::ratio<3, 4> a;
std::ratio<24, 32>::type b; b = a; //雖然沒有意義,但是編譯OK
但是std::ratio<24, 64>
與它們就不是同類:
std::ratio<3, 4> a;
std::ratio<24, 64>::type b; b = a; //ERROR,類型不匹配,不能賦值
2 std::ratio 的計算和比較
? std::ratio
還支持比率的加、減、乘、除運算,但是也都是在編譯器處理的,std::ratio_add()
方法的兩個模板參數(shù)也必須是std::ratio
類型,或std::ratio
類型的別名,但是不能是std::ratio
類型定義的變量名。以加法的使用方法為例:
using two_third = std::ratio<2, 3>;
using one_sixth = std::ratio<1, 6>;
using sum = std::ratio_add<two_third, one_sixth>;
std::cout << "2/3 + 1/6 = " << sum::num << '/' << sum::den << '\n';
輸出結(jié)果是:
2/3 + 1/6 = 5/6
除了四種基本運算,std::ratio
還支持大于、大于等于、小于、小于等于、等于和不等于共六個邏輯運算,以下是判斷兩個比率是否是大于關(guān)系的例子:
//C++ 11 的方式
if (std::ratio_greater<std::ratio<11, 12>, std::ratio<10, 11>>::value)
{std::cout << "11/12 > 10/11" "\n";
}
//C++ 17 的方式
if constexpr (std::ratio_greater_v<std::ratio<12, 13>, std::ratio<11, 12>>)
{std::cout << "12/13 > 11/12" "\n";
}
這些判斷也都是在編譯期進(jìn)行的,沒有任何運行開銷,最終運行的代碼應(yīng)該是這個樣子的:
if (true)
{std::cout << "11/12 > 10/11" "\n";
}
3 std::ratio 的預(yù)定義類型
? 為了方便代碼的書寫,std::ratio
還提供了很多預(yù)定義比率的別名,比如:
std::nano 相當(dāng)于 std::ratio<1, 1000000000>
std::micro 相當(dāng)于 std::ratio<1, 1000000>
std::milli 相當(dāng)于 std::ratio<1, 1000>
std::centi 相當(dāng)于 std::ratio<1, 100>
std::deci 相當(dāng)于 std::ratio<1, 10>
std::deca 相當(dāng)于 std::ratio<10, 1>
std::hecto 相當(dāng)于 std::ratio<100, 1>
std::kilo 相當(dāng)于 std::ratio<1000, 1>
std::mega 相當(dāng)于 std::ratio<1000000, 1>
std::giga 相當(dāng)于 std::ratio<1000000000, 1>
記住這些別名,有利于你看懂別人的代碼,自己寫代碼的時候,也可以少敲幾次鍵盤。
4 std::ratio 與編譯期計算
? std::ratio
的計算可以在編譯期完成的,它的設(shè)計本意不是用來做分?jǐn)?shù)庫使用,它更多的體現(xiàn)是不同數(shù)值之間變換的橋梁。只要變換一下比率,就可以讓一個值表達(dá)完全不同的意義,從這一點來說,std::ratio
比常量表達(dá)式更具有靈活性。
? 口說無憑,來看個例子,那就是本文要介紹的 C++ 時間庫中的duration
。duration
表示一段持續(xù)的時間,是個時間跨度,也稱為“時間間隔”。同一個時間間隔,可以用秒、毫秒來衡量,也可以用系統(tǒng)的 ticks 來衡量,在不同的衡量單位之間轉(zhuǎn)換,需要專門的計算。但是來看看結(jié)合了std::ratio
使用的duration
是如何做這種轉(zhuǎn)換的呢?來看個例子:
using namespace std::chrono;duration<long long, std::micro> micro_dura(5000000);
//duration<double, std::ratio<1, 1000000>> micro_dura(5000000); //與上面一行代碼等價auto sec_dura = duration_cast<duration<long long, std::ratio<1, 1>>>(micro_dura);
std::cout << "5000000 microseconds = " << sec_dura.count() << " seconds" << std::endl;
這段代碼定義了一個單位是微秒的時間間隔變量,名為micro_dura
,并賦值為 5000000 (微秒)。然后用duration_cast
將其轉(zhuǎn)換為以秒為單位的時間間隔sec_dura
,其值是 5(sec_dura.count()
就是返回這個時間間隔中有多少個計數(shù)單位(周期),每個單位的意義取決于duration
周期的定義)。上述代碼是duration_cast
是在編譯期間完成的,不占用運行時間。
? 實際上,C++ 的時間庫對各種時間間隔都有預(yù)定義的別名,比如上述代碼可以用更簡單的形式書寫:
using namespace std::chrono;microseconds micro_dura(5000000); //std::chrono::microseconds
auto aaa = duration_cast<seconds>(micro_dura);
std::cout << "5000000 microseconds = " << aaa.count() << " seconds" << std::endl;
再來看一個例子,統(tǒng)計一個 280 秒的時間間隔中包含多少個 70 秒的時間間隔(周期):
seconds sec(280); //等效于 duration<long long, std::ratio<1, 1>> sec(280);
auto bbb = duration_cast<duration<long long, std::ratio<70, 1>>>(sec);
assert((bbb.count() == 4));
這段代碼中的duration<long long, std::ratio<70, 1>>
表示定義了一種時間間隔類型,就是以 70 秒為周期的時間間隔類型。seconds
是時間庫預(yù)定義的時間間隔類型,單位是秒。
關(guān)注作者的算法專欄
https://blog.csdn.net/orbit/category_10400723.html
關(guān)注作者的出版物《算法的樂趣(第二版)》
https://www.ituring.com.cn/book/3180