Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
RandomGlobal.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* RandomGlobal.h (C) 2000-2017 */
9/* */
10/* Namespace for Random. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_RANDOM_RANDOMGLOBAL_H
13#define ARCANE_RANDOM_RANDOMGLOBAL_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
18#include <climits>
19#include <limits>
20
21#define RANDOM_BEGIN_NAMESPACE \
22 namespace random \
23 {
24#define RANDOM_END_NAMESPACE }
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane::random
30{
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35/*
36 * Copyright Jens Maurer 2000-2001
37 * Permission to use, copy, modify, sell, and distribute this software
38 * is hereby granted without fee provided that the above copyright notice
39 * appears in all copies and that both that copyright notice and this
40 * permission notice appear in supporting documentation,
41 *
42 * Jens Maurer makes no representations about the suitability of this
43 * software for any purpose. It is provided "as is" without express or
44 * implied warranty.
45 *
46 * See http://www.boost.org for most recent version including documentation.
47 *
48 * $Id: RandomGlobal.h 3932 2004-08-23 08:45:03Z grospelx $
49 *
50 * Revision history
51 * 2001-02-18 moved to individual header files
52 */
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57namespace utils
58{
59 template <class T, T min_val, T max_val>
61 {
62 public:
63
64 static const bool is_integral = true;
65 static const T const_min = min_val;
66 static const T const_max = max_val;
67 };
68
69 /*---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------*/
71
72 template <class T>
74
75 /*---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------*/
77
78 template <>
79 class integer_traits<int>
80 : public std::numeric_limits<int>
81 , public integer_traits_base<int, INT_MIN, INT_MAX>
82 {};
83
84 template <>
85 class integer_traits<unsigned int>
86 : public std::numeric_limits<unsigned int>
87 , public integer_traits_base<unsigned int, 0, UINT_MAX>
88 {};
89
90 template <>
91 class integer_traits<long>
92 : public std::numeric_limits<long>
93 , public integer_traits_base<long, LONG_MIN, LONG_MAX>
94 {};
95
96 template <>
97 class integer_traits<unsigned long>
98 : public std::numeric_limits<unsigned long>
99 , public integer_traits_base<unsigned long, 0, ULONG_MAX>
100 {};
101
102 /*---------------------------------------------------------------------------*/
103 /*---------------------------------------------------------------------------*/
104
105 template <bool is_signed>
106 struct do_add
107 {};
108
109 /*---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------*/
111
112 template <>
113 struct do_add<true>
114 {
115 template <class IntType>
116 static IntType add(IntType m, IntType x, IntType c)
117 {
118 x += (c - m);
119 if (x < 0)
120 x += m;
121 return x;
122 }
123 };
124
125 template <>
126 struct do_add<false>
127 {
128 template <class IntType>
129 static IntType add(IntType, IntType, IntType)
130 {
131 // difficult
132 throw FatalErrorException("const_mod::add with c too large");
133 return 0;
134 }
135 };
136
137 /*---------------------------------------------------------------------------*/
138 /*---------------------------------------------------------------------------*/
139
140 template <class IntType, IntType m>
141 class const_mod
142 {
143 public:
144
145 static IntType add(IntType x, IntType c)
146 {
147 if (c == 0)
148 return x;
149 else if (c <= traits::const_max - m) // i.e. m+c < max
150 return add_small(x, c);
151 else
152 return do_add<traits::is_signed>::add(m, x, c);
153 }
154
155 static IntType mult(IntType a, IntType x)
156 {
157 if (a == 1)
158 return x;
159 else if (m <= traits::const_max / a) // i.e. a*m <= max
160 return mult_small(a, x);
161 else if (traits::is_signed && (m % a < m / a))
162 return mult_schrage(a, x);
163 else {
164 // difficult
165#ifdef ARCANE_CHECK
166 throw FatalErrorException("const_mod::mult with a too large");
167#endif
168 return 0;
169 }
170 }
171
172 static IntType mult_add(IntType a, IntType x, IntType c)
173 {
174 if (m <= (traits::const_max - c) / a) // i.e. a*m+c <= max
175 return (a * x + c) % m;
176 else
177 return add(mult(a, x), c);
178 }
179
180 static IntType invert(IntType x)
181 {
182 return x == 0 ? 0 : invert_euclidian(x);
183 }
184
185 private:
186
187 typedef integer_traits<IntType> traits;
188
189 const_mod(); // don't instantiate
190
191 static IntType add_small(IntType x, IntType c)
192 {
193 x += c;
194 if (x >= m)
195 x -= m;
196 return x;
197 }
198
199 static IntType mult_small(IntType a, IntType x)
200 {
201 return a * x % m;
202 }
203
204 static IntType mult_schrage(IntType a, IntType value)
205 {
206 const IntType q = m / a;
207 const IntType r = m % a;
208
209 value = a * (value % q) - r * (value / q);
210 while (value <= 0)
211 value += m;
212 return value;
213 }
214
215 // invert c in the finite field (mod m) (m must be prime)
216 static IntType invert_euclidian(IntType c)
217 {
218 IntType l1 = 0;
219 IntType l2 = 1;
220 IntType n = c;
221 IntType p = m;
222 for (;;) {
223 IntType q = p / n;
224 l1 -= q * l2; // this requires a signed IntType!
225 p -= q * n;
226 if (p == 0)
227 return (l2 < 1 ? l2 + m : l2);
228 IntType q2 = n / p;
229 l2 -= q2 * l1;
230 n -= q2 * p;
231 if (n == 0)
232 return (l1 < 1 ? l1 + m : l1);
233 }
234 }
235 };
236
237 /*---------------------------------------------------------------------------*/
238 /*---------------------------------------------------------------------------*/
239
240 // The modulus is exactly the word size: rely on machine overflow handling.
241 // Due to a GCC bug, we cannot partially specialize in the presence of
242 // template value parameters.
243 template <>
244 class const_mod<unsigned int, 0>
245 {
246 typedef unsigned int IntType;
247
248 public:
249
250 static IntType add(IntType x, IntType c) { return x + c; }
251 static IntType mult(IntType a, IntType x) { return a * x; }
252 static IntType mult_add(IntType a, IntType x, IntType c) { return a * x + c; }
253
254 // m is not prime, thus invert is not useful
255 private: // don't instantiate
256
257 const_mod();
258 };
259
260 /*---------------------------------------------------------------------------*/
261 /*---------------------------------------------------------------------------*/
262
263 template <>
264 class const_mod<unsigned long, 0>
265 {
266 typedef unsigned long IntType;
267
268 public:
269
270 static IntType add(IntType x, IntType c) { return x + c; }
271 static IntType mult(IntType a, IntType x) { return a * x; }
272 static IntType mult_add(IntType a, IntType x, IntType c) { return a * x + c; }
273
274 // m is not prime, thus invert is not useful
275 private: // don't instantiate
276
277 const_mod();
278 };
279
280 /*---------------------------------------------------------------------------*/
281 /*---------------------------------------------------------------------------*/
282
283 /*
284 * Correctly compare two numbers whose types possibly differ in signedness.
285 * See boost::numeric_cast<> for the general idea.
286 * Most "if" statements involve only compile-time constants, so the
287 * optimizing compiler can do its job easily.
288 *
289 * With most compilers, the straightforward implementation produces a
290 * bunch of (legitimate) warnings. Some template magic helps, though.
291 */
292
293 template <bool signed1, bool signed2>
295 {};
296
297 template <>
298 struct do_compare<false, false>
299 {
300 // cast to the larger type is automatic with built-in types
301 template <class T1, class T2>
302 static bool equal(T1 x, T2 y) { return x == y; }
303 template <class T1, class T2>
304 static bool lessthan(T1 x, T2 y) { return x < y; }
305 };
306
307 template <>
308 struct do_compare<true, true> : public do_compare<false, false>
309 {};
310
311 template <>
312 struct do_compare<true, false>
313 {
314 template <class T1, class T2>
315 static bool equal(T1 x, T2 y) { return x >= 0 && static_cast<T2>(x) == y; }
316 template <class T1, class T2>
317 static bool lessthan(T1 x, T2 y) { return x < 0 || static_cast<T2>(x) < y; }
318 };
319
320 template <>
321 struct do_compare<false, true>
322 {
323 template <class T1, class T2>
324 static bool equal(T1 x, T2 y) { return y >= 0 && x == static_cast<T1>(y); }
325 template <class T1, class T2>
326 static bool lessthan(T1 x, T2 y) { return y >= 0 && x < static_cast<T1>(y); }
327 };
328
329 template <class T1, class T2>
330 int equal_signed_unsigned(T1 x, T2 y)
331 {
332 typedef std::numeric_limits<T1> x_traits;
333 typedef std::numeric_limits<T2> y_traits;
335 }
336
337 template <class T1, class T2>
338 int lessthan_signed_unsigned(T1 x, T2 y)
339 {
340 typedef std::numeric_limits<T1> x_traits;
341 typedef std::numeric_limits<T2> y_traits;
342 return do_compare<x_traits::is_signed, y_traits::is_signed>::lessthan(x, y);
343 }
344
345} // namespace utils
346
347/*---------------------------------------------------------------------------*/
348/*---------------------------------------------------------------------------*/
349
350} // namespace Arcane::random
351
352/*---------------------------------------------------------------------------*/
353/*---------------------------------------------------------------------------*/
354
355#endif
Arcane configuration file.