teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

追加

2016/06/25 00:44

投稿

Chironian
Chironian

スコア23274

answer CHANGED
@@ -64,3 +64,60 @@
64
64
 
65
65
  符号なし整数と符号付き整数の演算は定義されてます。
66
66
  unsined と intの演算は、intがunsignedへ変換されます。intをunsigendへ変換する時、intが負ならunsignedの最大値+1を加えて、intが2の補数表現でなくても2の補数表現の時と同じ結果になるよう定義されているようです。
67
+
68
+ ---
69
+ 【更に追加】
70
+ returnの計算に処理系依存が入ってましたので修正しました。
71
+ ついでにマクロを使ってC++11でも多少みやすくしました。(本音:C++14までメンテするのは面倒)
72
+
73
+ ```C++
74
+ #include <iostream>
75
+ #include <type_traits>
76
+ #include <limits>
77
+ #include <typeinfo>
78
+
79
+ template<typename T>
80
+ constexpr typename std::make_signed<T>::type removeExcess(T value)
81
+ {
82
+ typedef typename std::make_signed<T>::type Signed;
83
+ #define LIMIT (static_cast<T>(std::numeric_limits<Signed>::max())+1)
84
+ return (LIMIT < value)?(value-LIMIT):(static_cast<Signed>(value)-std::numeric_limits<Signed>::max()-1);
85
+ }
86
+
87
+ template<bool con, typename T> using enable_if_t = typename std::enable_if<con, T>::type;
88
+
89
+ template<typename T, enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr>
90
+ constexpr T a(T min, T max, T n)
91
+ {
92
+ return (n < min)
93
+ ? a(min, max, n + (max - min + 1) * ((min - n) / (max - min + 1) + 1))
94
+ : (n - min) % (max - min + 1) + min;
95
+ }
96
+
97
+ template<typename T, enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, std::nullptr_t> = nullptr>
98
+ constexpr T a(T min, T max, T n)
99
+ {
100
+ #if 0 // original
101
+ return ((n - min) % (max - min + 1) + max - min + 1) % (max - min + 1) + min;
102
+ #else
103
+ typedef typename std::make_unsigned<T>::type Unsigned;
104
+ #define N (static_cast<Unsigned>(std::numeric_limits<T>::max())+1+n)
105
+ #define MIN (static_cast<Unsigned>(std::numeric_limits<T>::max())+1+min)
106
+ #define MAX (static_cast<Unsigned>(std::numeric_limits<T>::max())+1+max)
107
+ #define MOD (MAX - MIN + 1)
108
+ return (MOD == 0)?n:removeExcess(a(MIN, MAX, N));
109
+ #endif
110
+ }
111
+
112
+ int main()
113
+ {
114
+ std::cout << a(-100, 100, 12) << "\n";
115
+ std::cout << a( 100, 200, 12) << "\n";
116
+ std::cout << a(-200, -100, -99) << "\n";
117
+ std::cout << a(-200, -100, 12) << "\n";
118
+ std::cout << a(std::numeric_limits<int>::min(), 1000, 12) << "\n";
119
+ std::cout << a(std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 12) << "\n";
120
+
121
+ return 0;
122
+ }
123
+ ```

1

追加

2016/06/25 00:44

投稿

Chironian
Chironian

スコア23274

answer CHANGED
@@ -54,4 +54,13 @@
54
54
 
55
55
  return 0;
56
56
  }
57
- ```
57
+ ```
58
+
59
+ ---
60
+ 【追加】
61
+ 書き忘れてました。下駄を履かせればOKと思う根拠は下記です。
62
+
63
+ [少し詳しい型変換の説明](http://www9.plala.or.jp/sgwr-t/detail/TypeConversion.html)をみてます。「JIS X 3010 プログラム言語C」を参照していると書かれているので、規格的に大丈夫と期待。
64
+
65
+ 符号なし整数と符号付き整数の演算は定義されてます。
66
+ unsined と intの演算は、intがunsignedへ変換されます。intをunsigendへ変換する時、intが負ならunsignedの最大値+1を加えて、intが2の補数表現でなくても2の補数表現の時と同じ結果になるよう定義されているようです。