exactmath.cpp
1 #include "exactmath.hpp"
2 double const splitter = 134217729;
3 
4 namespace {
5  void fastTwoSumTail(double const a, double const b, double const x, double& y)
6  {
7  // const double bVirt = x - a;
8  y = b - (x - a);
9  }
10 }
11 
12 void fastTwoSum(double const a, double const b, double& res, double& err)
13 {
14  res = a + b;
15  fastTwoSumTail(a, b, res, err);
16 }
17 
18 namespace {
19  void fastTwoDiffTail(double const a, double const b, double const x, double& y)
20  {
21  const double bVirt = a - x;
22  y = bVirt - b;
23  }
24 }
25 
26 void fastTwoDiff(double a, double b, double& res, double& err)
27 {
28  res = a - b;
29  fastTwoDiffTail(a, b, res, err);
30 }
31 
32 namespace {
33  double twoSumTail(double const a, double const b, double const x)
34  {
35  double bVirt = x - a;
36  double aVirt = x - bVirt;
37  bVirt = b - bVirt;
38  aVirt = a - aVirt;
39  return aVirt + bVirt;
40  }
41 }
42 
43 void twoSum(double a, double b, double& res, double& err)
44 {
45  res = a + b;
46  err = twoSumTail(a, b, res);
47 }
48 
49 namespace {
50  void twoDiffTail(double const a, double const b, double const x, double& y)
51  {
52  double bVirt = a - x;
53  double aVirt = x + bVirt;
54  bVirt -= b;
55  aVirt = a - aVirt;
56  y = aVirt + bVirt;
57  }
58 }
59 
60 void twoDiff(double a, double b, double& res, double& err)
61 {
62  res = a - b;
63  twoDiffTail(a, b, res, err);
64 }
65 
66 void split(double num, double& high, double& low)
67 {
68  double c = splitter * num;
69  double temp = c - num;
70  high = c - temp;
71  low = num - high;
72 }
73 
74 namespace {
75  void twoProductTail(double const a, double const b, double const x, double& y)
76  {
77  double ahi, alo, bhi, blo;
78  split(a, ahi, alo);
79  split(b, bhi, blo);
80  y = x - (ahi * bhi);
81  y -= (alo * bhi);
82  y -= (ahi * blo);
83  y = (alo * blo) - y;
84  }
85 }
86 
87 void twoProduct(double a, double b, double& res, double& err)
88 {
89  res = a * b;
90  twoProductTail(a, b, res, err);
91 }
92 
93 namespace {
94  void squareTail(double const a, double const x, double& y)
95  {
96  double high, low;
97  split(a, high, low);
98  y = x - (high * high);
99  y -= ((high + high) * low);
100  y = (low * low) - y;
101  }
102 }
103 
104 void square(double num, double& res, double& err)
105 {
106  res = num * num;
107  squareTail(num, res, err);
108 }
109 
110 boost::array<double,3> twoOneSum(boost::array<double,2> const& a, double b)
111 {
112  boost::array<double,3> res;
113  double tmp;
114  twoSum(a[0], b, tmp, res[0]);
115  twoSum(a[1], tmp, res[2], res[1]);
116  return res;
117 }
118 
119 boost::array<double,3> twoOneDiff(boost::array<double,2> const& a, double b)
120 {
121  boost::array<double,3> res;
122  double tmp;
123  twoDiff(a[0], b, tmp, res[0]);
124  twoSum(a[1], tmp, res[2], res[1]);
125  return res;
126 }
127 
128 vector<double> twoTwoSum(boost::array<double,2> const& a, boost::array<double,2> const& b)
129 {
130  vector<double> res(4);
131  double tmp1, tmp2, tmp3;
132  twoSum(a[0], b[0], tmp1, res[0]);
133  twoSum(a[1], tmp1, tmp2, tmp3);
134  twoSum(tmp3, b[1], tmp1, res[1]);
135  twoSum(tmp2, tmp1, res[3], res[2]);
136  return res;
137 }
138 
139 vector<double> twoTwoDiff(boost::array<double,2> const& a, boost::array<double,2> const& b)
140 {
141  vector<double> res(4);
142  double tmp1, tmp2, tmp3;
143  twoDiff(a[1], b[1], tmp1, res[0]);
144  twoSum(a[0], tmp1, tmp2, tmp3);
145  twoDiff(tmp3, b[0], tmp1, res[1]);
146  twoSum(tmp2, tmp1, res[3], res[2]);
147  return res;
148 }
149 
150 vector<double> growExpansionZeroElim(vector<double> const& e, double b)
151 {
152  vector<double> ans;
153  ans.reserve(8);
154  double R1, R2, res; //Temp variables to store values.
155 
156  R1 = b; //The remainder to add to the expansion.
157  for (size_t i = 0; i < e.size(); ++i)
158  {
159  twoSum(R1, e[i], R2, res); //Adding the remainder to the current number in the expansion.
160  R1 = R2; //Updating remainder.
161  if (res != 0.0)
162  { //Ignoring 0.
163  ans.push_back(res); //Creating the result expansion.
164  }
165  }
166  if ((R1 != 0.0) || ans.empty())
167  { //No numbers were previously added to result expansion.
168  ans.push_back(R1);
169  }
170  return ans; //Returns the result vector.
171 }
172 
173 vector<double> expansionSumZeroElim(vector<double> const& e, vector<double> const& f)
174 {
175  vector<double> temp, ans;
176  temp.reserve(8);
177  ans.reserve(8);
178  double Q, Qnew, current;
179 
180  Q = f[0];
181  for (size_t i = 0; i < e.size(); i++)
182  {
183  twoSum(Q, e[i], Qnew, current);
184  temp.push_back(current);
185  Q = Qnew;
186  }
187  temp.push_back(Q);
188  for (size_t i = 1; i < f.size(); i++)
189  {
190  Q = f[i];
191  for (size_t j = i; j < temp.size(); j++)
192  {
193  current = temp[j];
194  twoSum(Q, current, Qnew, temp[j]);
195  Q = Qnew;
196  }
197  temp.push_back(Q);
198  }
199  for (size_t i = 0; i < temp.size(); i++)
200  {
201  if (fabs(temp[i]) > 0)
202  {
203  ans.push_back(temp[i]);
204  }
205  }
206  if (ans.empty())
207  {
208  ans.push_back(0.0);
209  }
210  return ans;
211 }
212 
213 vector<double> fastExpansionSumZeroElim(vector<double> const& e, vector<double> const& f)
214 {
215  vector<double> ans;
216  ans.reserve(10);
217  double Q, Qnew;
218  double hh;
219  double eNow, fNow;
220  unsigned int eIndex, fIndex;
221 
222  eNow = e[0];
223  fNow = f[0];
224  eIndex = fIndex = 0;
225  if ((fNow > eNow) == (fNow > -eNow))
226  {
227  Q = eNow;
228  eIndex++;
229  if (eIndex <e.size())
230  {
231  eNow = e[eIndex];
232  }
233  }
234  else
235  {
236  Q = fNow;
237  fIndex++;
238  if (fIndex <f.size())
239  {
240  fNow = f[fIndex];
241  }
242  }
243  if ((eIndex < e.size()) && (fIndex < f.size()))
244  {
245  if ((fNow > eNow) == (fNow > -eNow))
246  {
247  fastTwoSum(eNow, Q, Qnew, hh);
248  eIndex++;
249  if (eIndex <e.size())
250  {
251  eNow = e[eIndex];
252  }
253  }
254  else
255  {
256  fastTwoSum(fNow, Q, Qnew, hh);
257  fIndex++;
258  if (fIndex <f.size())
259  {
260  fNow = f[fIndex];
261  }
262  }
263  Q = Qnew;
264  if (hh != 0.0)
265  {
266  ans.push_back(hh);
267  }
268  while ((eIndex < e.size()) && (fIndex <f.size()))
269  {
270  if ((fNow > eNow) == (fNow > -eNow))
271  {
272  twoSum(Q, eNow, Qnew, hh);
273  eIndex++;
274  if (eIndex < e.size())
275  {
276  eNow = e[eIndex];
277  }
278  }
279  else
280  {
281  twoSum(Q, fNow, Qnew, hh);
282  fIndex++;
283  if (fIndex < f.size())
284  {
285  fNow = f[fIndex];
286  }
287  }
288  Q = Qnew;
289  if (hh != 0.0)
290  {
291  ans.push_back(hh);
292  }
293  }
294  }
295  while (eIndex < e.size())
296  {
297  twoSum(Q, eNow, Qnew, hh);
298  eIndex++;
299  if (eIndex < e.size())
300  {
301  eNow = e[eIndex];
302  }
303  Q = Qnew;
304  if (hh != 0.0)
305  {
306  ans.push_back(hh);
307  }
308  }
309  while (fIndex < f.size())
310  {
311  twoSum(Q, fNow, Qnew, hh);
312  fIndex++;
313  if (fIndex < f.size())
314  {
315  fNow = f[fIndex];
316  }
317  Q = Qnew;
318  if (hh != 0.0)
319  {
320  ans.push_back(hh);
321  }
322  }
323  if ((Q != 0.0) || ans.empty())
324  {
325  ans.push_back(Q);
326  }
327  return ans;
328 }
329 
330 vector<double> linearExpansionSumZeroElim(vector<double> const& e, vector<double> const& f)
331 {
332  vector<double> ans;
333  ans.reserve(8);
334  double Q, q, hh;
335  double Qnew;
336  double R;
337  double g0;
338 
339  double enow = e.front();
340  double fnow = f.front();
341  size_t eindex = 0;
342  size_t findex = 0;
343  if ((fnow > enow) == (fnow > -enow))
344  {
345  g0 = enow;
346  eindex++;
347  if (eindex < e.size())
348  {
349  enow = e[eindex];
350  }
351  }
352  else
353  {
354  g0 = fnow;
355  findex++;
356  if (findex < f.size())
357  {
358  fnow = f[findex];
359  }
360  }
361  if ((eindex <e.size()) && ((findex >= f.size()) || ((fnow > enow) == (fnow > -enow))))
362  {
363  fastTwoSum(enow, g0, Qnew, q);
364  eindex++;
365  if (eindex < e.size())
366  {
367  enow = e[eindex];
368  }
369  }
370  else
371  {
372  fastTwoSum(fnow, g0, Qnew, q);
373  findex++;
374  if (findex <f.size())
375  {
376  fnow = f[findex];
377  }
378  }
379  Q = Qnew;
380  for (size_t count = 2, endp=e.size() + f.size(); count < endp; count++)
381  {
382  if ((eindex < e.size()) && ((findex >= f.size()) || ((fnow > enow) == (fnow > -enow))))
383  {
384  fastTwoSum(enow, q, R, hh);
385  eindex++;
386  if (eindex < e.size())
387  {
388  enow = e[eindex];
389  }
390  }
391  else
392  {
393  fastTwoSum(fnow, q, R, hh);
394  findex++;
395  if (findex < f.size())
396  {
397  fnow = f[findex];
398  }
399  }
400  twoSum(Q, R, Qnew, q);
401  Q = Qnew;
402  if (fabs(hh) > 0)
403  {
404  ans.push_back(hh);
405  }
406  }
407  if (fabs(q) > 0) {
408  ans.push_back(q);
409  }
410  if ((Q != 0.0) || ans.empty()) {
411  ans.push_back(Q);
412  }
413  return ans;
414 }
415 
416 void scaleExpansionZeroElim(vector<double> const& e, double b,vector<double>
417  &ans)
418 {
419  ans.clear();
420  ans.reserve(10);
421  double Q, hh;
422  double product0, product1,sum;
423  int eindex;
424 
425  twoProduct(e[0], b, Q, hh);
426  if (fabs(hh) > 0)
427  {
428  ans.push_back(hh);
429  }
430  int n=static_cast<int>(e.size());
431  for (eindex = 1; eindex<n; ++eindex)
432  {
433  twoProduct(e[static_cast<size_t>(eindex)], b, product1, product0);
434  twoSum(Q, product0,sum, hh);
435  if (fabs(hh) > 0)
436  {
437  ans.push_back(hh);
438  }
439  fastTwoSum(product1,sum, Q, hh);
440  if (fabs(hh) > 0)
441  {
442  ans.push_back(hh);
443  }
444  }
445  if ((Q != 0.0) || ans.empty()) {
446  ans.push_back(Q);
447  }
448 }
449 
450 vector<double> compress(vector<double> const& e)
451 {
452  vector<double> temp, ans;
453  ans.reserve(8);
454 
455  int bottom = static_cast<int>(e.size()) - 1;
456  double Q = e[static_cast<size_t>(bottom)];
457  for (int eindex =static_cast<int>(e.size()) - 2; eindex >= 0; eindex--)
458  {
459  const double enow = e[static_cast<size_t>(eindex)];
460  double q, Qnew;
461  fastTwoSum(Q, enow, Qnew, q);
462  if (fabs(q) > 0)
463  {
464  temp.insert(temp.begin(), Qnew);
465  bottom--;
466  Q = q;
467  }
468  else
469  {
470  Q = Qnew;
471  }
472  }
473  for (size_t i = static_cast<size_t>(bottom) + 1; i <e.size(); i++)
474  {
475  const double current = temp[i];
476  double q, Qnew;
477  fastTwoSum(current, Q, Qnew, q);
478  if (fabs(q) > 0)
479  {
480  ans.push_back(q);
481  }
482  Q = Qnew;
483  }
484  ans.push_back(Q);
485  return ans;
486 }
487 
488 double estimate(vector<double> const& e)
489 {
490  double Q;
491 
492  Q = e[0];
493  for (size_t i = 1; i < e.size(); i++)
494  {
495  Q += e[i];
496  }
497  return Q;
498 }
vector< double > expansionSumZeroElim(vector< double > const &e, vector< double > const &f)
Adds up two expansions.
Definition: exactmath.cpp:173
void twoDiff(double a, double b, double &res, double &err)
Difference between two numbers.
Definition: exactmath.cpp:60
boost::array< double, 3 > twoOneSum(boost::array< double, 2 > const &a, double b)
Calculates the sum of a two-expansion and a double.
Definition: exactmath.cpp:110
double estimate(vector< double > const &e)
Calculate a double precision approximation of the expansion.
Definition: exactmath.cpp:488
vector< double > growExpansionZeroElim(vector< double > const &e, double b)
Adds a scalar to an existing expansion.
Definition: exactmath.cpp:150
Exact math.
vector< double > twoTwoSum(boost::array< double, 2 > const &a, boost::array< double, 2 > const &b)
Calculates the sum of two two-expansions.
Definition: exactmath.cpp:128
void twoProduct(double a, double b, double &res, double &err)
Product of two number.
Definition: exactmath.cpp:87
vector< double > compress(vector< double > const &e)
Compresses an expansion.
Definition: exactmath.cpp:450
void twoSum(double a, double b, double &res, double &err)
Calculates the sum of a and b.
Definition: exactmath.cpp:43
void fastTwoDiff(double a, double b, double &res, double &err)
Subtracts two numbers.
Definition: exactmath.cpp:26
boost::array< double, 3 > twoOneDiff(boost::array< double, 2 > const &a, double b)
Calculates the difference between a two-expansion and a double.
Definition: exactmath.cpp:119
vector< double > twoTwoDiff(boost::array< double, 2 > const &a, boost::array< double, 2 > const &b)
Calculates the difference between two two-expansions.
Definition: exactmath.cpp:139
void split(double num, double &high, double &low)
Splits a given number into two, Used for multiplication.
Definition: exactmath.cpp:66
vector< double > fastExpansionSumZeroElim(vector< double > const &e, vector< double > const &f)
Adds up two expansions.
Definition: exactmath.cpp:213
void scaleExpansionZeroElim(vector< double > const &e, double b, vector< double > &result)
Multiplies a scalar by an expansion.
Definition: exactmath.cpp:416
void fastTwoSum(double a, double b, double &res, double &err)
Calculates the sum of two numbers.
Definition: exactmath.cpp:12
vector< double > linearExpansionSumZeroElim(vector< double > const &e, vector< double > const &f)
Adds up two expansions.
Definition: exactmath.cpp:330
void square(double num, double &res, double &err)
Calculates the square of a number.
Definition: exactmath.cpp:104