詳しくはC++11中ratioコンパイル期間点数(一)
25057 ワード
スコアについては、C++の標準ライブラリにはこのようなクラスは提供されておらず、必要に応じて完全に自分で実現することができるが、C++11は
このクラスでは、コンパイル期間のスコアを具体的に指定し、コンパイル期間の演算を実行できます(最も簡略化できます).また、コンパイル期間は安全です.これはソースコードで見ることができます.分母が0のような異常はコンパイル期間で取得できます.
まず、この
このDemoは
では、分子 分母 次に、値を見てみましょう.
分子分母には簡略化があり、簡略化の原理はそれらの最大公約数を同時に除くことである.
また,ソースコードから
したがって、クラス外には次の2つの変数の定義があります.
この2つの文は、コンパイル期間中に分母がゼロであるかどうか、数値がオーバーフローしているかどうかを確認します.
まず、ここでは
コンパイル期間シンボルを求める
コンパイル期間は絶対値を求め,
コンパイル期間は2つの定数の最大公約数を求める.
これは最も興味深いもので,テンプレートの再帰継承にユークリッド再帰アルゴリズムを加えて実現され,再帰の終点偏特化テンプレートは
ここまで、
最後に、次の表があります.これは、標準ライブラリでユーザーが作成しやすいタイプの再定義です.
名前
たんい
y o c t o yocto yocto
1 1 , 000 , 000 , 000 , 000 , 000 , 000\cfrac{1}{1,000,000,000,000,000,000} 1,000,000,000,000,000,0001
f e m t o femto femto
1 1 , 000 , 000 , 000 , 000 , 000\cfrac{1}{1,000,000,000,000,000} 1,000,000,000,000,0001
p i c o pico pico
1 1 , 000 , 000 , 000 , 000\cfrac{1}{1,000,000,000,000} 1,000,000,000,0001
n a n o nano nano
1 1 , 000 , 000 , 000\cfrac{1}{1,000,000,000} 1,000,000,0001
m i c r o micro micro
1 1 , 000 , 000\cfrac{1}{1,000,000} 1,000,0001
m i l l i milli milli
1 1 , 000\cfrac{1}{1,000} 1,0001
c e n t i centi centi
1 100\cfrac{1}{100} 1001
d e c i deci deci
1 10\cfrac{1}{10} 101
d e c a deca deca
10 10 10
h e c t o hecto hecto
100 100 100
k i l o kilo kilo
1 , 000 1,000 1,000
m e g a mega mega
1 , 000 , 000 1,000,000 1,000,000
g i g a giga giga
1 , 000 , 000 , 000 1,000,000,000 1,000,000,000
t e r a tera tera
1 , 000 , 000 , 0000 , 000 1,000,000,0000,000 1,000,000,0000,000
p e t a peta peta
1 , 000 , 000 , 0000 , 000 , 000 1,000,000,0000,000,000 1,000,000,0000,000,000
e x a exa exa
1 , 000 , 000 , 0000 , 000 , 000 , 000 1,000,000,0000,000,000,000 1,000,000,0000,000,000,000
コードは次のとおりです.
std::ratio
ヘッダファイルに定義されたコンパイル期間定数スコアクラス
を提供する.このクラスでは、コンパイル期間のスコアを具体的に指定し、コンパイル期間の演算を実行できます(最も簡略化できます).また、コンパイル期間は安全です.これはソースコードで見ることができます.分母が0のような異常はコンパイル期間で取得できます.
まず、この
std::ratio
の使い方を見てみましょう.template<long long N, long long D>
std::ostream & operator << (std::ostream & os, const std::ratio<N, D> && r)
{
return os << r.num << " / " << r.den << std::endl;
}
int main()
{
std::cout << std::ratio<5, 3>();
std::cout << std::ratio<2, 2>();
std::cout << std::ratio<0, 3>();
std::cout << std::ratio<4, 6>();
std::cout << std::ratio<-4, 6>();
std::cout << std::ratio<4, -6>();
std::cout << std::ratio<-4, -6>();
return 0;
}
このDemoは
std::ratio
の特性を詳細に示すことができる.では、
ratio
はどのように実現されているのか、まずソースコードを見てみましょう./**
* @brief Provides compile-time rational arithmetic.
*
* This class template represents any finite rational number with a
* numerator and denominator representable by compile-time constants of
* type intmax_t. The ratio is simplified when instantiated.
*
* For example:
* @code
* std::ratio<7,-21>::num == -1;
* std::ratio<7,-21>::den == 3;
* @endcode
*
*/
template<intmax_t _Num, intmax_t _Den = 1>
struct ratio
{
static_assert(_Den != 0, "denominator cannot be zero");
static_assert(_Num >= -__INTMAX_MAX__ && _Den >= -__INTMAX_MAX__,
"out of range");
// Note: sign(N) * abs(N) == N
static constexpr intmax_t num =
_Num * __static_sign<_Den>::value / __static_gcd<_Num, _Den>::value;
static constexpr intmax_t den =
__static_abs<_Den>::value / __static_gcd<_Num, _Den>::value;
typedef ratio<num, den> type;
};
template<intmax_t _Num, intmax_t _Den>
constexpr intmax_t ratio<_Num, _Den>::num;
template<intmax_t _Num, intmax_t _Den>
constexpr intmax_t ratio<_Num, _Den>::den;
ratio
には、2つの静的定数メンバー変数しかありません.num
den
static constexpr intmax_t num =
_Num * __static_sign<_Den>::value / __static_gcd<_Num, _Den>::value;
static constexpr intmax_t den =
__static_abs<_Den>::value / __static_gcd<_Num, _Den>::value;
分子分母には簡略化があり、簡略化の原理はそれらの最大公約数を同時に除くことである.
また,ソースコードから
ratio
が簡略化されると分母の負の番号が分子にシフトすることがわかる.したがって、クラス外には次の2つの変数の定義があります.
template<intmax_t _Num, intmax_t _Den>
constexpr intmax_t ratio<_Num, _Den>::num;
template<intmax_t _Num, intmax_t _Den>
constexpr intmax_t ratio<_Num, _Den>::den;
ratio
はコンパイル期間が安全であると以前に述べたが,これはC++11の新しい特性static_assert
のおかげで,コンパイル期間は断言した.static_assert(_Den != 0, "denominator cannot be zero");
static_assert(_Num >= -__INTMAX_MAX__ && _Den >= -__INTMAX_MAX__, "out of range");
この2つの文は、コンパイル期間中に分母がゼロであるかどうか、数値がオーバーフローしているかどうかを確認します.
ratio
はこの場所で終わったようですが、コードに現れた__static_gcd
などはまだ説明されていません.この一連のソースコードを見てみましょう.まず、ここでは
type_traits
の基石であるintegral_constant
が大量に使われていることを宣言します.具体的にはC++11のtype_を参照してください.traitsの基石-integral_constant.これらはすべてintegral_constant
の応用で、よく体得することができます.__static_sign
コンパイル期間シンボルを求める
template<intmax_t _Pn>
struct __static_sign : integral_constant<intmax_t, (_Pn < 0) ? -1 : 1> { };
__static_abs
コンパイル期間は絶対値を求め,
__static_sign
を用いてシンボルを求め,その後負の正の性質を用いて絶対値を得た.template<intmax_t _Pn>
struct __static_abs : integral_constant<intmax_t, _Pn * __static_sign<_Pn>::value> { };
__static_gcd
コンパイル期間は2つの定数の最大公約数を求める.
これは最も興味深いもので,テンプレートの再帰継承にユークリッド再帰アルゴリズムを加えて実現され,再帰の終点偏特化テンプレートは
integral_constant
,最終__static_gcd<6, 4>::value == 2
から継承される.template<intmax_t _Pn, intmax_t _Qn>
struct __static_gcd : __static_gcd<_Qn, (_Pn % _Qn)> { };
/// partial specialization
template<intmax_t _Pn>
struct __static_gcd<_Pn, 0> : integral_constant<intmax_t, __static_abs<_Pn>::value> { };
template<intmax_t _Qn>
struct __static_gcd<0, _Qn> : integral_constant<intmax_t, __static_abs<_Qn>::value> { };
ここまで、
ratio
の紹介は本当に一段落したが、標準ライブラリはratio
を定義し、ratio
にレンガを追加する補助類も必然的にある.例えば、スコアは、C++11におけるratioコンパイル期間スコア(一)を詳細に説明するために、加算除算することができる.最後に、次の表があります.これは、標準ライブラリでユーザーが作成しやすいタイプの再定義です.
名前
たんい
y o c t o yocto yocto
1 1 , 000 , 000 , 000 , 000 , 000 , 000\cfrac{1}{1,000,000,000,000,000,000} 1,000,000,000,000,000,0001
f e m t o femto femto
1 1 , 000 , 000 , 000 , 000 , 000\cfrac{1}{1,000,000,000,000,000} 1,000,000,000,000,0001
p i c o pico pico
1 1 , 000 , 000 , 000 , 000\cfrac{1}{1,000,000,000,000} 1,000,000,000,0001
n a n o nano nano
1 1 , 000 , 000 , 000\cfrac{1}{1,000,000,000} 1,000,000,0001
m i c r o micro micro
1 1 , 000 , 000\cfrac{1}{1,000,000} 1,000,0001
m i l l i milli milli
1 1 , 000\cfrac{1}{1,000} 1,0001
c e n t i centi centi
1 100\cfrac{1}{100} 1001
d e c i deci deci
1 10\cfrac{1}{10} 101
d e c a deca deca
10 10 10
h e c t o hecto hecto
100 100 100
k i l o kilo kilo
1 , 000 1,000 1,000
m e g a mega mega
1 , 000 , 000 1,000,000 1,000,000
g i g a giga giga
1 , 000 , 000 , 000 1,000,000,000 1,000,000,000
t e r a tera tera
1 , 000 , 000 , 0000 , 000 1,000,000,0000,000 1,000,000,0000,000
p e t a peta peta
1 , 000 , 000 , 0000 , 000 , 000 1,000,000,0000,000,000 1,000,000,0000,000,000
e x a exa exa
1 , 000 , 000 , 0000 , 000 , 000 , 000 1,000,000,0000,000,000,000 1,000,000,0000,000,000,000
コードは次のとおりです.
typedef ratio<1, 1000000000000000000> atto;
typedef ratio<1, 1000000000000000> femto;
typedef ratio<1, 1000000000000> pico;
typedef ratio<1, 1000000000> nano;
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
typedef ratio<1, 100> centi;
typedef ratio<1, 10> deci;
typedef ratio< 10, 1> deca;
typedef ratio< 100, 1> hecto;
typedef ratio< 1000, 1> kilo;
typedef ratio< 1000000, 1> mega;
typedef ratio< 1000000000, 1> giga;
typedef ratio< 1000000000000, 1> tera;
typedef ratio< 1000000000000000, 1> peta;
typedef ratio< 1000000000000000000, 1> exa;