C++ Library Extensions 2022.12.09
To help learn modern C++ programming
007-integer.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2#include <tpf_safe_type.hpp>
3#include <numeric>
4
6auto nl = tpf::nl;
8
9namespace types = tpf::types;
10namespace safe = tpf::safe_type;
11
13{
14 // this function displays integral type information
16
17 // I removed bool type from the integral type list
18 stream <<"Integral types are: " <<
19 types::integral_list_t{} // this displays integral types
20 << endl;
21
22 stream << "Signed integral types are: "
24
25 stream << "Unsigned integral types are: "
27
28 stream <<"Integer types are: " <<
29 types::integer_list_t{} // this displays integer types
30 << endl;
31
32 stream << "Signed integer types are: "
34
35 stream << "Unsigned integer types are: "
37}
38
39template<typename Type> // template parameter clause
41 // for SFINAE out, SFINAE: Substitution Failure Is Not an Error
42 // Allowed Types: char, short, int, long, long long
43safe_add(Type a, Type b)
44{
45 /*
46 lower_bound <= a + b <= upper_bound ... should hold
47
48 where lower_bound = std::numeric_limits<Type>::min(),
49 upper_bound = std::numeric_limits<Type>::max()
50
51 when a > 0 && b > 0, that is, both are positive
52
53 a + b <= upper_bound should hold
54 a <= upper_bound - b (1)
55
56 when a < 0 && b < 0, that is, both are negative
57 lower_bound <= a + b should hold
58
59 lower_bound - b <= a (2)
60 */
61
62// constexpr auto lower_bound = std::numeric_limits<Type>::min();
63//
64constexpr auto upper_bound = std::numeric_limits<Type>::max();
65 constexpr auto lower_bound = safe::limits_min<Type>;
66 constexpr auto upper_bound = safe::limits_max<Type>;
67
68
69 if( a > 0 && b > 0) // both are positive
70 {
71 if(a <= upper_bound - b)
72 return a + b;
73 else // overflow
74 {
75 tpf::sstream os;
76 os << "overflow: a = " << a
77 <<", b = " << b;
78
80 }
81 }
82 else if ( a < 0 && b < 0) // both are negative
83 {
84 if(lower_bound - b <= a)
85 return a + b;
86 else // overflow
87 {
88 tpf::sstream os;
89 os << "overflow: a = " << a
90 <<", b = " << b;
91
93 }
94 }
95 else // a and b have different sign,
96 // one is positive and the other negative
97 return a + b;
98}
99
100template<typename Type> // template parameter clause
102 // for SFINAE out, SFINAE: Substitution Failure Is Not an Error
103 // Allowed Types: char, short, int, long, long long
104safe_sub(Type a, Type b)
105{
106 return safe_add(a, -b);
107}
108
109template<typename Type> // template parameter clause
111 // for SFINAE out, SFINAE: Substitution Failure Is Not an Error
112 // Allowed Types: unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long
113safe_add(Type a, Type b)
114{
115 /*
116 0 <= a + b <= upper_bound
117
118 a + b <= upper_bound
119
120 => a <= upper_bound - b should hold
121 */
122
123 // constexpr auto upper_bound = std::numeric_limits<Type>::max();
124 constexpr auto upper_bound = safe::limits_max<Type>;
125
126
127 if(a <= upper_bound - b)
128 return a + b;
129 else // overflow
130 {
131 tpf::sstream os;
132 os << "overflow: a = " << a
133 <<", b = " << b;
134
136 }
137}
138
139template<typename Type> // template parameter clause
141 // for SFINAE out, SFINAE: Substitution Failure Is Not an Error
142 // Allowed Types: unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long
143safe_sub(Type a, Type b)
144{
145 /*
146 0 <= a - b should hold
147 b <= a ... should hold
148 */
149
150 if(b <= a)
151 return a - b;
152 else // overflow
153 {
154 tpf::sstream os;
155 os << "overflow: a = " << a
156 <<", b = " << b;
157
159 }
160}
161
162template<typename Type>
163types::enable_if_integral_t<Type> // return type, '
164 // in case of multiplication, we don't
165 // need to classify signed and unsigned separately
166safe_mul(Type a, Type b)
167{
168 /*
169 auto rlt = a * b;
170
171 (1)
172 if b == 0, we can return rlt == 0
173
174 (2)
175 if b != 0 and rlt / b == a
176
177 (3)
178 otherwise, overflow
179 */
180 auto rlt = a * b;
181
182 if( (b == 0) || (rlt / b == a) ) // we are using short-circuit feature of C++
183 return rlt; // in C++, A || B, if A is true, B is not executed
184 // B is only executed when A is false,
185 // this property is called "short-circuit"
186 else // overflow
187 {
188 tpf::sstream os;
189 os << "overflow: a = " << a
190 <<", b = " << b;
191
193 }
194}
195
196template<typename Type>
197types::enable_if_integral_t<Type> // return type, '
198 // in case of multiplication, we don't
199 // need to classify signed and unsigned separately
200safe_div(Type a, Type b)
201{
202 if(b != 0)
203 return a / b;
204 else // overflow
205 {
206 tpf::sstream os;
207 os << "division by zero: a = " << a
208 <<", b = " << b;
209
211 }
212}
213
215{
216 try
217 {
218 // constexpr auto int_lower_bound = std::numeric_limits<int>::min();
219 // constexpr auto int_upper_bound = std::numeric_limits<int>::max();
220
221 // constexpr auto unsigned_lower_bound = std::numeric_limits<unsigned>::min();
222 // constexpr auto unsigned_upper_bound = std::numeric_limits<unsigned>::max();
223
224 constexpr auto int_lower_bound = safe::limits_min<int>;
225 constexpr auto int_upper_bound = safe::limits_max<int>;
226
227 constexpr auto unsigned_lower_bound = safe::limits_min<unsigned>;
228 constexpr auto unsigned_upper_bound = safe::limits_max<unsigned>;
229
230
231 auto signed_a = 3;
232 auto signed_b = 2;
233
234 auto signed_add = safe_add(signed_a, signed_b);
235 stream <<signed_a << " + "<< signed_b << " = " << signed_add << endl;
236
237 auto signed_zero = 1;
238
239 auto signed_div = safe_div(signed_a, signed_zero);
240 stream <<signed_a << " / "<< signed_zero << " = " << signed_div << endl;
241
242 // auto signed_c = int_upper_bound;
243 auto signed_c = 5;
244 auto signed_d = 2;
245
246 auto signed_mul = safe_mul(signed_c, signed_d);
247 stream <<signed_c << " * "<< signed_d << " = " << signed_mul << endl;
248
249 } catch(std::exception& e)
250 {
251 stream << e << endl;
252 }
253
254}
255
256int main()
257{
258 // display_integral_types();
260}
types::enable_if_integral_t< Type > safe_div(Type a, Type b)
tpf::sstream stream
Definition: 007-integer.cpp:5
types::enable_if_signed_integral_t< Type > safe_sub(Type a, Type b)
types::enable_if_integral_t< Type > safe_mul(Type a, Type b)
void examples_for_safe_arithmetic()
void display_integral_types()
Definition: 007-integer.cpp:12
types::enable_if_signed_integral_t< Type > safe_add(Type a, Type b)
Definition: 007-integer.cpp:43
auto endl
Definition: 007-integer.cpp:7
auto nl
Definition: 007-integer.cpp:6
int main()
std::string integral_type_info()
Defines safe type operation.
Type to string name conversions are defined.
Definition: 31-visit.cpp:7
hidden::enable_if_integral_t< Type, ReturnType > enable_if_integral_t
Definition: tpf_types.hpp:5080
hidden::enable_if_signed_integral_t< Type, ReturnType > enable_if_signed_integral_t
Definition: tpf_types.hpp:5083
hidden::enable_if_unsigned_integral_t< Type, ReturnType > enable_if_unsigned_integral_t
Definition: tpf_types.hpp:5086
constexpr auto endl
Definition: tpf_output.hpp:973
constexpr auto nl
Definition: tpf_output.hpp:971
This type is used to manipulate type list.
Definition: tpf_types.hpp:956
Stream output operators << are implemented.
This file implements safe arithmetic.
#define Tpf_ThrowDebugException(debug_message)
Throw a debug_exception with message as argument.
Definition: tpf_types.hpp:1416