Chris@16
|
1
|
Chris@16
|
2 // Copyright 2012 John Maddock. Distributed under the Boost
|
Chris@16
|
3 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MP_CPP_INT_CHECKED_HPP
|
Chris@16
|
7 #define BOOST_MP_CPP_INT_CHECKED_HPP
|
Chris@16
|
8
|
Chris@16
|
9 namespace boost{ namespace multiprecision{ namespace backends{ namespace detail{
|
Chris@16
|
10
|
Chris@16
|
11 //
|
Chris@16
|
12 // Simple routines for performing checked arithmetic with a builtin arithmetic type.
|
Chris@16
|
13 // Note that this is not a complete header, it must be included as part of boost/multiprecision/cpp_int.hpp.
|
Chris@16
|
14 //
|
Chris@16
|
15
|
Chris@16
|
16 inline void raise_overflow(std::string op)
|
Chris@16
|
17 {
|
Chris@16
|
18 BOOST_THROW_EXCEPTION(std::overflow_error("overflow in " + op));
|
Chris@16
|
19 }
|
Chris@16
|
20 inline void raise_add_overflow()
|
Chris@16
|
21 {
|
Chris@16
|
22 raise_overflow("addition");
|
Chris@16
|
23 }
|
Chris@16
|
24 inline void raise_subtract_overflow()
|
Chris@16
|
25 {
|
Chris@16
|
26 BOOST_THROW_EXCEPTION(std::range_error("Subtraction resulted in a negative value, but the type is unsigned"));
|
Chris@16
|
27 }
|
Chris@16
|
28 inline void raise_mul_overflow()
|
Chris@16
|
29 {
|
Chris@16
|
30 raise_overflow("multiplication");
|
Chris@16
|
31 }
|
Chris@16
|
32 inline void raise_div_overflow()
|
Chris@16
|
33 {
|
Chris@16
|
34 raise_overflow("division");
|
Chris@16
|
35 }
|
Chris@16
|
36
|
Chris@16
|
37 template <class A>
|
Chris@16
|
38 inline A checked_add_imp(A a, A b, const mpl::true_&)
|
Chris@16
|
39 {
|
Chris@16
|
40 if(a > 0)
|
Chris@16
|
41 {
|
Chris@16
|
42 if((b > 0) && ((integer_traits<A>::const_max - b) < a))
|
Chris@16
|
43 raise_add_overflow();
|
Chris@16
|
44 }
|
Chris@16
|
45 else
|
Chris@16
|
46 {
|
Chris@16
|
47 if((b < 0) && ((integer_traits<A>::const_min - b) > a))
|
Chris@16
|
48 raise_add_overflow();
|
Chris@16
|
49 }
|
Chris@16
|
50 return a + b;
|
Chris@16
|
51 }
|
Chris@16
|
52 template <class A>
|
Chris@16
|
53 inline A checked_add_imp(A a, A b, const mpl::false_&)
|
Chris@16
|
54 {
|
Chris@16
|
55 if((integer_traits<A>::const_max - b) < a)
|
Chris@16
|
56 raise_add_overflow();
|
Chris@16
|
57 return a + b;
|
Chris@16
|
58 }
|
Chris@16
|
59 template <class A>
|
Chris@16
|
60 inline A checked_add(A a, A b, const mpl::int_<checked>&)
|
Chris@16
|
61 {
|
Chris@16
|
62 return checked_add_imp(a, b, boost::is_signed<A>());
|
Chris@16
|
63 }
|
Chris@16
|
64 template <class A>
|
Chris@16
|
65 inline A checked_add(A a, A b, const mpl::int_<unchecked>&)
|
Chris@16
|
66 {
|
Chris@16
|
67 return a + b;
|
Chris@16
|
68 }
|
Chris@16
|
69
|
Chris@16
|
70 template <class A>
|
Chris@16
|
71 inline A checked_subtract_imp(A a, A b, const mpl::true_&)
|
Chris@16
|
72 {
|
Chris@16
|
73 if(a > 0)
|
Chris@16
|
74 {
|
Chris@16
|
75 if((b < 0) && ((integer_traits<A>::const_max + b) < a))
|
Chris@16
|
76 raise_subtract_overflow();
|
Chris@16
|
77 }
|
Chris@16
|
78 else
|
Chris@16
|
79 {
|
Chris@16
|
80 if((b > 0) && ((integer_traits<A>::const_min + b) > a))
|
Chris@16
|
81 raise_subtract_overflow();
|
Chris@16
|
82 }
|
Chris@16
|
83 return a - b;
|
Chris@16
|
84 }
|
Chris@16
|
85 template <class A>
|
Chris@16
|
86 inline A checked_subtract_imp(A a, A b, const mpl::false_&)
|
Chris@16
|
87 {
|
Chris@16
|
88 if(a < b)
|
Chris@16
|
89 raise_subtract_overflow();
|
Chris@16
|
90 return a - b;
|
Chris@16
|
91 }
|
Chris@16
|
92 template <class A>
|
Chris@16
|
93 inline A checked_subtract(A a, A b, const mpl::int_<checked>&)
|
Chris@16
|
94 {
|
Chris@16
|
95 return checked_subtract_imp(a, b, boost::is_signed<A>());
|
Chris@16
|
96 }
|
Chris@16
|
97 template <class A>
|
Chris@16
|
98 inline A checked_subtract(A a, A b, const mpl::int_<unchecked>&)
|
Chris@16
|
99 {
|
Chris@16
|
100 return a - b;
|
Chris@16
|
101 }
|
Chris@16
|
102
|
Chris@16
|
103 template <class A>
|
Chris@16
|
104 inline A checked_multiply(A a, A b, const mpl::int_<checked>&)
|
Chris@16
|
105 {
|
Chris@16
|
106 BOOST_MP_USING_ABS
|
Chris@16
|
107 if(a && (integer_traits<A>::const_max / abs(a) < abs(b)))
|
Chris@16
|
108 raise_mul_overflow();
|
Chris@16
|
109 return a * b;
|
Chris@16
|
110 }
|
Chris@16
|
111 template <class A>
|
Chris@16
|
112 inline A checked_multiply(A a, A b, const mpl::int_<unchecked>&)
|
Chris@16
|
113 {
|
Chris@16
|
114 return a * b;
|
Chris@16
|
115 }
|
Chris@16
|
116
|
Chris@16
|
117 template <class A>
|
Chris@16
|
118 inline A checked_divide(A a, A b, const mpl::int_<checked>&)
|
Chris@16
|
119 {
|
Chris@16
|
120 if(b == 0)
|
Chris@16
|
121 raise_div_overflow();
|
Chris@16
|
122 return a / b;
|
Chris@16
|
123 }
|
Chris@16
|
124 template <class A>
|
Chris@16
|
125 inline A checked_divide(A a, A b, const mpl::int_<unchecked>&)
|
Chris@16
|
126 {
|
Chris@16
|
127 return a / b;
|
Chris@16
|
128 }
|
Chris@16
|
129
|
Chris@16
|
130 template <class A>
|
Chris@16
|
131 inline A checked_left_shift(A a, unsigned long long shift, const mpl::int_<checked>&)
|
Chris@16
|
132 {
|
Chris@16
|
133 if(a && shift)
|
Chris@16
|
134 {
|
Chris@16
|
135 if((shift > sizeof(A) * CHAR_BIT) || (a >> (sizeof(A) * CHAR_BIT - shift)))
|
Chris@16
|
136 BOOST_THROW_EXCEPTION(std::overflow_error("Shift out of range"));
|
Chris@16
|
137 }
|
Chris@16
|
138 return a << shift;
|
Chris@16
|
139 }
|
Chris@16
|
140 template <class A>
|
Chris@16
|
141 inline A checked_left_shift(A a, unsigned long long shift, const mpl::int_<unchecked>&)
|
Chris@16
|
142 {
|
Chris@16
|
143 return (shift >= sizeof(A) * CHAR_BIT) ? 0 : a << shift;
|
Chris@16
|
144 }
|
Chris@16
|
145
|
Chris@16
|
146 }}}} // namespaces
|
Chris@16
|
147
|
Chris@16
|
148 #endif
|
Chris@16
|
149
|