User-defined literals で固定長の Boost.Multiprecision を生成の続き
昨日の続き。
昨日とは違い、その数値が収まる 2のn乗のビット幅を使用するようにしてみました。
[ソース]
#include <boost/multiprecision/cpp_int.hpp> template<char ...cs> struct chars{}; constexpr bool operator <=(chars<>, chars<>){ return true; } template<char ...cs> constexpr bool operator <=(chars<>, chars<cs...>){ return true; } template<char ...cs> constexpr bool operator <=(chars<cs...>, chars<>){ return false; } template<char top1, char ...cs1, char top2, char ...cs2> constexpr bool operator <=(chars<top1, cs1...>, chars<top2, cs2...>){ return sizeof...(cs1) < sizeof...(cs2) ? true : sizeof...(cs1) > sizeof...(cs2) ? false : top1 < top2 ? true : top1 > top2 ? false : chars<cs1...>{} <= chars<cs2...>{}; } template<char ...cs> constexpr chars<cs...> operator "" _chars(){ return {}; } template<typename Precision> constexpr std::size_t bit(Precision&& rhs){ return rhs <= 127_chars ? 8 : rhs <= 32767_chars ? 16 : rhs <= 2147483647_chars ? 32 : rhs <= 9223372036854775807_chars ? 64 : rhs <= 170141183460469231731687303715884105727_chars ? 128 : rhs <= 57896044618658097711785492504343953926634992332820282019728792003956564819967_chars ? 256 : rhs <= 6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042047_chars ? 512 : rhs <= 89884656743115795386465259539451236680898848947115328636715040578866337902750481566354238661203768010560056939935696678829394884407208311246423715319737062188883946712432742638151109800623047059726541476042502884419075341171231440736956555270413618581675255342293149119973622969239858152417678164812112068607_chars ? 1024 : 2048; } template<int Precision> using cpp_int = boost::multiprecision::number< boost::multiprecision::cpp_int_backend< Precision, Precision, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void > >; template<char ...cs> cpp_int<bit(chars<cs...>{})> operator "" _cpp_int(){ char const str[] = { cs..., '\0' }; return cpp_int<bit(chars<cs...>{})>(str); } #include <iostream> #include <limits> int main(){ auto hoge = 432984_cpp_int; std::cout << hoge << std::endl; std::cout << std::numeric_limits<decltype(hoge)>::digits << std::endl; auto n = 573147844013817084101_cpp_int; std::cout << n << std::endl; std::cout << std::numeric_limits<decltype(n)>::digits << std::endl; auto m = 927372692193078999176_cpp_int; std::cout << m << std::endl; std::cout << std::numeric_limits<decltype(m)>::digits << std::endl; auto o = n + m; std::cout << o << std::endl; auto cpp128 = 170141183460469231731687303715884105727_cpp_int; std::cout << cpp128 << std::endl; std::cout << std::numeric_limits<decltype(cpp128)>::digits << std::endl; auto cpp256 = 57896044618658097711785492504343953926634992332820282019728792003956564819967_cpp_int; std::cout << cpp256 << std::endl; std::cout << std::numeric_limits<decltype(cpp256)>::digits << std::endl; return 0; }
[出力]
432984 32 573147844013817084101 128 927372692193078999176 128 1500520536206896083277 170141183460469231731687303715884105727 128 57896044618658097711785492504343953926634992332820282019728792003956564819967 256
まぁ毎回 int128_t や int256_t を使用するよりはマシかな。
桁が大きすぎるとどの型を使えばいいのかすぐにはわからないだろうし、そういう意味では利便性がありそうな気がしないでもない。
(もっとも、実際に数値リテラルから固定長の Boost.Multiprecision を生成する場合は、長さを決め打ちで使いそうですが。
あと余談ですが数値が大きすぎてそのままではコンパイル時に比較ができないので文字として値を比較しています。
User-defined literals を使ったら思ったよりも便利だった。
constexpr ばんざーい。
[boost]
- ver 1.53.0