Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
HPReal.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 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/* HPReal.h (C) 2000-2019 */
9/* */
10/* Réel haute-précision. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_UTILS_HPREAL_H
13#define ARCANE_UTILS_HPREAL_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/utils/Numeric.h"
18
19#include <iosfwd>
20
21/*---------------------------------------------------------------------------*/
22/*---------------------------------------------------------------------------*/
23
24namespace Arcane
25{
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28/*!
29 * \brief Classe implémentant un réel Haute Précision.
30
31 Cette classe est basée sur l'article:
32
33 Obtaining identical results with double precision global accuracy on
34 different numbers of processors in parallel particle Monte Carlo
35 simulations (Mathew A. Cleveland, Thomas A. Brunner, Nicholas A. Gentile,
36 jeffrey A. Keasler) in Journal Of Computational Physics 251 (2013) 223-236.
37
38 Les opérations possibles sont l'accumulation (operator+=()),
39 la réduction (reduce()) et la conversion vers un Real (toReal()).
40 Il n'est pas possible de faire d'autres opérations telles que les divisions
41 où les multiplications.
42
43 Pour se conformer au type 'Real' classique, le constructeur par défaut
44 de cette classe ne fait aucune initialisation.
45
46 La méthode toReal() permet de convertir le HPReal en un Réel classique.
47 Le fonctionnement typique est le suivant:
48
49 \code
50 * HPReal r(0.0);
51 * ArrayView<Real> x = ...;
52 * for( Integer i=0, n=x.size(); i<n; ++i ){
53 * // Accumule la valeur
54 * r += x[i];
55 * }
56 * Real final_r = r.toReal();
57 \endcode
58
59 Evolution 12/18/18 :
60
61 Correction erreur de l'algorithme de base de static HPReal _doTwoSum(Real a, Real b)
62
63 Real sum_error = (a - (value-approx_b) + (b-approx_b));
64
65 est devenu (en accord avec la Ref 1)
66
67 Real sum_error = (a - (value-approx_b)) + (b-approx_b);
68
69 Correction erreur de static HPReal _doQuickTwoSum(Real a,Real b)
70
71 il faut tester si a>b et inverser a et b si cela n'est pas le cas (voir Ref 2,3,4)
72
73 Modification de Accumulate et de Reduce,
74 Accumulate et de Reduce etaient basées sur la Ref 1 qui a pour base la Ref 4
75
76 Ajout des produits comme proposés dans la ref 2 (en accord avec la Ref 5)
77 de HPReal*Real ou HPreal*HPreal (on prend la meme valeur de p pour la
78 fonction SPLIT() que la Ref 2,4,5)
79
80 Attention le produit Real*Real de la Ref 4 (p.4) n'est pas ecrit de la meme facon que celui
81 de la Ref 2 (p.2), 5 (p.3)
82
83 +++++++++++++++++
84
85 Globalement les algo de reductions ou les erreurs sont cumulées uniquement
86 avec une addition sont moins bons
87
88 L'algo 6 de DD_TWOSUM [Ref 2] est aussi moins bon:
89
90 \code
91 static HPReal accumulate(Real a,MYHPReal b)
92 {
93 HPReal x(_doTwoSum(a,b.value()));
94 Real d= x.correction() + b.correction();
95 HPReal u(_doQuickTwoSum(x.value(),d));
96 return _doQuickTwoSum(u.value(),u.correction());
97 }
98 \endcode
99
100 ou
101
102 \code
103 HPReal reduce(HPReal a,HPReal b)
104 {
105 HPReal x(_doTwoSum(a.value(),b.value()));
106 HPReal y(_doTwoSum(a.correction(),b.correction()));
107 Real d= x.correction() + y.value();
108 HPReal u(_doQuickTwoSum(x.value(),d));
109 Real w=y.correction()+u.correction();
110 return _doQuickTwoSum(u.value(),w);
111 }
112 \endcode
113
114 Des tests sur des millions de valeurs positives comme négatives ont été effectués
115 pour l'additon,la multiplication et la division dans des ordres différents.
116
117 Je n'ai pas réussi à faire apparaitre dans un cas simple une différence de resultat entre l'algo
118 proposée pour la somme et celui code initialement.
119
120 Références
121 ----------
122
123 Ref 1
124 Obtaining identical results with double precision global accuracy on
125 different numbers of processors in parallel particle Monte Carlo
126 simulations (Mathew A. Cleveland, Thomas A. Brunner, Nicholas A. Gentile,
127 jeffrey A. Keasler) in Journal Of Computational Physics 251 (2013) 223-236.
128
129 Ref 2
130 Automatic Source-to-Source error compensation of floating-point programs
131 L.Thevenoux, Ph langlois, Mathieu Martel
132 HAL Id: hal-01158399
133
134 Ref 3
135 Numerical validation of compensated summation algorithms withs stochastic arithmetic
136 S.Gaillat, F.Jézéquel , R.Picot
137 Published in Electronic Notes in Theoritical Computer Science
138
139 ou
140
141 Numerical validation of compensated algorithms withs stochastic arithmetic
142 S.Gaillat, F.Jézéquel , R.Picot
143 Published in Applied Mathematics and Computation 329 (2018)339-363
144
145 Ref 4
146 Library for Double-Double and Quad-Double Arithmetic
147 December 29, 2007
148 Yozo Hida Xiaoye Li D.H.Bailey
149
150 Ref 5
151 Accurate floating point Product and exponentation
152 S.Graillat
153 HAL ID: hal-00164607
154
155 Ref 6
156 A floating point technique for extending the avaible precision
157 T.J.Dekker
158 Numeri.Math 18, 224-242 (1971)
159*/
160class ARCANE_UTILS_EXPORT HPReal
161{
162 public:
163 /*!
164 * \brief Constructeur par défaut sans initialisation.
165 */
167
168 //! Créé un réel HP avec la valeur \a value et la correction \a correction
169 explicit HPReal(double avalue)
170 : m_value(avalue)
171 , m_correction(0.0)
172 {}
173
174 //! Créé un réel HP avec la valeur \a value et la correction \a correction
175 HPReal(double avalue, double acorrection)
176 : m_value(avalue)
177 , m_correction(acorrection)
178 {}
179
180 //! Valeur interne. En général, il faut utiliser toReal()
181 Real value() const { return m_value; }
182
183 //! Correction interne.
184 Real correction() const { return m_correction; }
185
186 //! Ajoute un Real en conservant l'erreur.
187 void operator+=(Real v)
188 {
189 *this = accumulate(v, *this);
190 }
191
192 //! Ajoute un HPReal \a v en conservant l'erreur (réduction)
193 inline void operator+=(HPReal v)
194 {
195 *this = reduce(*this, v);
196 }
197
198 //! Converti l'instance en un Real.
199 inline Real toReal() const
200 {
201 return value() + correction();
202 }
203
204 //! Ajoute un HPReal \a v en conservant l'erreur (réduction)
206 {
207 return reduce(*this, b);
208 }
209
210 //! multiplie un Real en conservant l'erreur.
211 void operator*=(Real v)
212 {
213 *this = product(v, *this);
214 }
215
216 //! multiplie un HPReal \a v en conservant l'erreur (réduction)
217 inline void operator*=(HPReal v)
218 {
219 *this = product(*this, v);
220 }
221
222 //! multiplie un Real en conservant l'erreur.
223 void operator/=(Real v)
224 {
225 *this = div2(v, *this);
226 }
227
228 //! multiplie un HPReal \a v en conservant l'erreur (réduction)
229 inline void operator/=(HPReal v)
230 {
231 *this = div2(*this, v);
232 }
233
234 /*!
235 * \brief Lit un HPReal sur le flot \a i.
236 * Le couple est lu sous la forme de deux valeurs de type #Real.
237 */
238 std::istream& assign(std::istream& i);
239 //! Ecrit l'instance sur le flot \a o lisible par un assign()
240 std::ostream& print(std::ostream& o) const;
241 //! Ecrit l'instance sur le flot \a o sous la forme (x,y)
242 std::ostream& printPretty(std::ostream& o) const;
243
244 public:
245 //! Valeur zéro.
246 static HPReal zero() { return HPReal(0.0); }
247
248 public:
249 static HPReal accumulate(Real a, HPReal b)
250 {
251 HPReal x(_doTwoSum(a, b.value()));
252 Real c = x.correction() + b.correction();
253 return _doQuickTwoSum(x.value(), c);
254 }
255
256 // Mpi passe par la
257 static HPReal reduce(HPReal a, HPReal b)
258 {
259 HPReal x(_doTwoSum(a.value(), b.value()));
260 Real c = x.correction() + a.correction() + b.correction();
261 return _doQuickTwoSum(x.value(), c);
262 }
263
264 // algo 11 de AC_TWOPRODUCTS Ref 2
265 static HPReal product(HPReal a, HPReal b)
266 {
267 HPReal x(_doTwoProducts(a.value(), b.value()));
268 Real w = x.correction() + (a.value() * b.correction() + b.value() * a.correction());
269 return HPReal(x.value(), w);
270 }
271 // algo 11 de AC_TWOPRODUCTS Ref 2
272 static HPReal product(Real a, HPReal b)
273 {
274 HPReal x(_doTwoProducts(a, b.value()));
275 Real w = x.correction() + (a * b.correction());
276 return HPReal(x.value(), w);
277 }
278
279 // algo div2 Ref 6 div2 = a/b
280 // j'ai mis des parentheses dans l'evaluation de w pour forcer un ordre quelque soir les options de compil
281 // ATTENTION les 2 dernieres lignes de l'algo div2 ne sont pas mises (on ne renormalise pas)
282 // l'algo "mul2" les contient aussi et ne les a pas mises aussi pour "product" car l'algo 11 de la Ref 2 n'en n'a pas (a mon humble avis)
283 static HPReal div2(HPReal a, HPReal b)
284 {
285 Real c = a.value() / b.value();
286 HPReal u(_doTwoProducts(c, b.value()));
287 Real w = ((((a.value() - u.value()) + -u.correction()) + a.correction()) - c * b.correction()) / b.value();
288 return HPReal(c, w);
289 }
290 // algo div2 Ref 6 div2 = a/b
291 static HPReal div2(Real b, HPReal a)
292 {
293 Real c = a.value() / b;
294 HPReal u(_doTwoProducts(c, b));
295 Real w = (((a.value() - u.value()) + -u.correction()) + a.correction()) / b;
296 return HPReal(c, w);
297 }
298
299 private:
300 Real m_value;
301 Real m_correction;
302
303 private:
304 // correction des ()
305 static HPReal _doTwoSum(Real a, Real b)
306 {
307 Real value = a + b;
308 Real approx_b = value - a;
309 Real sum_error = (a - (value - approx_b)) + (b - approx_b);
310 return HPReal(value, sum_error);
311 }
312 // correction tests de la valeur de a et b et on mets des valeurs absolues
313 static HPReal _doQuickTwoSum(Real a1, Real b1)
314 {
315 Real a = a1;
316 Real b = b1;
317 if (std::abs(b1) > std::abs(a1)) {
318 a = b1;
319 b = a1;
320 }
321 Real value = a + b;
322 Real error_value = (b - (value - a));
323 return HPReal(value, error_value);
324 }
325 // algo 4 ref 2 ou algo 2.4 ref 3 ou algo 6 p.4
326 static HPReal _doTwoProducts(Real a, Real b)
327 {
328 Real x = a * b;
329 HPReal aw = SPLIT(a);
330 HPReal bw = SPLIT(b);
331 Real y = aw.correction() * bw.correction() - (((x - aw.value() * bw.value()) - aw.correction() * bw.value()) - aw.value() * bw.correction());
332 return HPReal(x, y);
333 }
334 static HPReal SPLIT(Real a)
335 {
336 const Real f = 134217729; // 1+ 2^ceil(52/2);
337 Real c = f * a;
338 Real x = c - (c - a);
339 Real y = a - x;
340 return HPReal(x, y);
341 }
342};
343
344/*---------------------------------------------------------------------------*/
345/*---------------------------------------------------------------------------*/
346
347inline bool
348operator<(const HPReal& a, const HPReal& b)
349{
350 return a.toReal() < b.toReal();
351}
352
353inline bool
354operator>(const HPReal& a, const HPReal& b)
355{
356 return a.toReal() > b.toReal();
357}
358
359inline bool
360operator==(const HPReal& a, const HPReal& b)
361{
362 return a.value() == b.value() && a.correction() == b.correction();
363}
364
365inline bool
366operator!=(const HPReal& a, const HPReal& b)
367{
368 return !operator==(a, b);
369}
370
371inline HPReal
372operator+(const HPReal& a, const HPReal& b)
373{
374 return HPReal::reduce(a, b);
375}
376
377/*---------------------------------------------------------------------------*/
378/*---------------------------------------------------------------------------*/
379
380inline std::ostream&
381operator<<(std::ostream& o, HPReal t)
382{
383 return t.printPretty(o);
384}
385
386inline std::istream&
387operator>>(std::istream& i, HPReal& t)
388{
389 return t.assign(i);
390}
391
392/*---------------------------------------------------------------------------*/
393/*---------------------------------------------------------------------------*/
394
395} // End namespace Arcane
396
397/*---------------------------------------------------------------------------*/
398/*---------------------------------------------------------------------------*/
399
400#endif
Classe implémentant un réel Haute Précision.
Definition HPReal.h:161
void operator*=(HPReal v)
multiplie un HPReal v en conservant l'erreur (réduction)
Definition HPReal.h:217
HPReal()
Constructeur par défaut sans initialisation.
Definition HPReal.h:166
static HPReal zero()
Valeur zéro.
Definition HPReal.h:246
HPReal reduce(HPReal b) const
Ajoute un HPReal v en conservant l'erreur (réduction)
Definition HPReal.h:205
Real toReal() const
Converti l'instance en un Real.
Definition HPReal.h:199
void operator+=(Real v)
Ajoute un Real en conservant l'erreur.
Definition HPReal.h:187
HPReal(double avalue)
Créé un réel HP avec la valeur value et la correction correction.
Definition HPReal.h:169
void operator/=(Real v)
multiplie un Real en conservant l'erreur.
Definition HPReal.h:223
void operator+=(HPReal v)
Ajoute un HPReal v en conservant l'erreur (réduction)
Definition HPReal.h:193
HPReal(double avalue, double acorrection)
Créé un réel HP avec la valeur value et la correction correction.
Definition HPReal.h:175
Real correction() const
Correction interne.
Definition HPReal.h:184
void operator*=(Real v)
multiplie un Real en conservant l'erreur.
Definition HPReal.h:211
void operator/=(HPReal v)
multiplie un HPReal v en conservant l'erreur (réduction)
Definition HPReal.h:229
Real value() const
Valeur interne. En général, il faut utiliser toReal()
Definition HPReal.h:181
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
bool operator<(const Item &item1, const Item &item2)
Compare deux entités.
Definition Item.h:533
std::istream & operator>>(std::istream &istr, eItemKind &item_kind)
Opérateur d'entrée depuis un flot.
std::ostream & operator<<(std::ostream &ostr, eItemKind item_kind)
Opérateur de sortie sur un flot.
double Real
Type représentant un réel.