@@ -88,42 +88,6 @@ inline std::array<RealNumber, 2> two_diff(RealNumber const a,
8888 return {{ x, y }};
8989}
9090
91- // constexpr power-method, helper for splitter
92- template
93- <
94- typename RealNumber
95- >
96- constexpr RealNumber int_pow (RealNumber const base,
97- int exp,
98- RealNumber out = 1.0 )
99- {
100- return exp < 1 ? out :
101- int_pow<RealNumber>(base*base, exp/2 , (exp % 2 ) ? out*base : out);
102- }
103-
104- // consexpr method to compute 2^s + 1 as in Theorem 17, page 18
105- template
106- <
107- typename RealNumber
108- >
109- constexpr RealNumber splitter ()
110- {
111- return int_pow<RealNumber>(2.0 ,
112- (std::numeric_limits<RealNumber>::digits + 1 ) / 2 ) + 1 ;
113- }
114-
115- // see theorem 17, page 18
116- template
117- <
118- typename RealNumber
119- >
120- inline std::array<RealNumber, 2 > split (RealNumber const a) {
121- RealNumber c = splitter<RealNumber>() * a;
122- RealNumber a_big = c - a;
123- RealNumber a_hi = c - a_big;
124- return {{ a_hi, a - a_hi }};
125- }
126-
12791// see theorem 18, page 19
12892template
12993<
@@ -133,12 +97,7 @@ inline RealNumber two_product_tail(RealNumber const a,
13397 RealNumber const b,
13498 RealNumber const x)
13599{
136- std::array<RealNumber, 2 > a_expansion = split (a);
137- std::array<RealNumber, 2 > b_expansion = split (b);
138- RealNumber err1 = x - (a_expansion[0 ] * b_expansion[0 ]);
139- RealNumber err2 = err1 - (a_expansion[1 ] * b_expansion[0 ]);
140- RealNumber err3 = err2 - (a_expansion[0 ] * b_expansion[1 ]);
141- return (a_expansion[1 ] * b_expansion[1 ]) - err3;
100+ return std::fma (a, b, -x);
142101}
143102
144103// see theorem 18, page 19
@@ -199,45 +158,63 @@ inline int fast_expansion_sum_zeroelim(
199158{
200159 std::array<RealNumber, 2 > Qh;
201160 int i_e = 0 , i_f = 0 , i_h = 0 ;
202- if (std::abs (f[0 ]) > std::abs (e[0 ])) {
161+ if (std::abs (f[0 ]) > std::abs (e[0 ]))
162+ {
203163 Qh[0 ] = e[i_e++];
204- } else {
164+ }
165+ else
166+ {
205167 Qh[0 ] = f[i_f++];
206168 }
207169 i_h = 0 ;
208- if ((i_e < m) && (i_f < n)) {
209- if (std::abs (f[i_f]) > std::abs (e[i_e])) {
170+ if ((i_e < m) && (i_f < n))
171+ {
172+ if (std::abs (f[i_f]) > std::abs (e[i_e]))
173+ {
210174 Qh = fast_two_sum (e[i_e++], Qh[0 ]);
211- } else {
175+ }
176+ else
177+ {
212178 Qh = fast_two_sum (f[i_f++], Qh[0 ]);
213179 }
214- if (Qh[1 ] != 0.0 ) {
180+ if (Qh[1 ] != 0.0 )
181+ {
215182 h[i_h++] = Qh[1 ];
216183 }
217- while ((i_e < m) && (i_f < n)) {
218- if (std::abs (f[i_f]) > std::abs (e[i_e])) {
184+ while ((i_e < m) && (i_f < n))
185+ {
186+ if (std::abs (f[i_f]) > std::abs (e[i_e]))
187+ {
219188 Qh = two_sum (Qh[0 ], e[i_e++]);
220- } else {
189+ }
190+ else
191+ {
221192 Qh = two_sum (Qh[0 ], f[i_f++]);
222193 }
223- if (Qh[1 ] != 0.0 ) {
194+ if (Qh[1 ] != 0.0 )
195+ {
224196 h[i_h++] = Qh[1 ];
225197 }
226198 }
227199 }
228- while (i_e < m) {
200+ while (i_e < m)
201+ {
229202 Qh = two_sum (Qh[0 ], e[i_e++]);
230- if (Qh[1 ] != 0.0 ) {
203+ if (Qh[1 ] != 0.0 )
204+ {
231205 h[i_h++] = Qh[1 ];
232206 }
233207 }
234- while (i_f < n) {
208+ while (i_f < n)
209+ {
235210 Qh = two_sum (Qh[0 ], f[i_f++]);
236- if (Qh[1 ] != 0.0 ) {
211+ if (Qh[1 ] != 0.0 )
212+ {
237213 h[i_h++] = Qh[1 ];
238214 }
239215 }
240- if ((Qh[0 ] != 0.0 ) || (i_h == 0 )) {
216+ if ((Qh[0 ] != 0.0 ) || (i_h == 0 ))
217+ {
241218 h[i_h++] = Qh[0 ];
242219 }
243220 return i_h;
@@ -259,83 +236,76 @@ inline int scale_expansion_zeroelim(
259236{
260237 std::array<RealNumber, 2 > Qh = two_product (e[0 ], b);
261238 int i_h = 0 ;
262- if (Qh[1 ] != 0 ) {
239+ if (Qh[1 ] != 0 )
240+ {
263241 h[i_h++] = Qh[1 ];
264242 }
265- for (int i_e = 1 ; i_e < e_non_zeros; i_e++) {
243+ for (int i_e = 1 ; i_e < e_non_zeros; i_e++)
244+ {
266245 std::array<RealNumber, 2 > Tt = two_product (e[i_e], b);
267246 Qh = two_sum (Qh[0 ], Tt[1 ]);
268- if (Qh[1 ] != 0 ) {
247+ if (Qh[1 ] != 0 )
248+ {
269249 h[i_h++] = Qh[1 ];
270250 }
271251 Qh = fast_two_sum (Tt[0 ], Qh[0 ]);
272- if (Qh[1 ] != 0 ) {
252+ if (Qh[1 ] != 0 )
253+ {
273254 h[i_h++] = Qh[1 ];
274255 }
275256 }
276- if ((Qh[0 ] != 0.0 ) || (i_h == 0 )) {
257+ if ((Qh[0 ] != 0.0 ) || (i_h == 0 ))
258+ {
277259 h[i_h++] = Qh[0 ];
278260 }
279261 return i_h;
280262}
281263
282- // see page 38, Figure 21 for the calculations, notation follows the notation in the figure.
264+ template <typename RealNumber>
265+ struct vec2d
266+ {
267+ RealNumber x;
268+ RealNumber y;
269+ };
270+
283271template
284272<
285273 typename RealNumber,
286- std::size_t Robustness = 3
274+ std::size_t Robustness
287275>
288- inline RealNumber orient2d (std::array<RealNumber, 2 > const & p1,
289- std::array<RealNumber, 2 > const & p2,
290- std::array<RealNumber, 2 > const & p3)
276+ inline RealNumber orient2dtail (vec2d<RealNumber> const & p1,
277+ vec2d<RealNumber> const & p2,
278+ vec2d<RealNumber> const & p3,
279+ std::array<RealNumber, 2 >& t1,
280+ std::array<RealNumber, 2 >& t2,
281+ std::array<RealNumber, 2 >& t3,
282+ std::array<RealNumber, 2 >& t4,
283+ std::array<RealNumber, 2 >& t5_01,
284+ std::array<RealNumber, 2 >& t6_01,
285+ RealNumber const & magnitude
286+ )
291287{
292- if (Robustness == 0 ) {
293- return (p1[0 ]-p3[0 ])*(p2[1 ]-p3[1 ]) - (p1[1 ]-p3[1 ])*(p2[0 ] - p3[0 ]);
294- }
295- std::array<RealNumber, 2 > t1, t2, t3, t4;
296- t1[0 ] = p1[0 ] - p3[0 ];
297- t2[0 ] = p2[1 ] - p3[1 ];
298- t3[0 ] = p1[1 ] - p3[1 ];
299- t4[0 ] = p2[0 ] - p3[0 ];
300- std::array<RealNumber, 2 > t5_01, t6_01;
301- t5_01[0 ] = t1[0 ] * t2[0 ];
302- t6_01[0 ] = t3[0 ] * t4[0 ];
303- RealNumber det = t5_01[0 ] - t6_01[0 ];
304- if ( (t5_01[0 ] > 0 && t6_01[0 ] <= 0 ) || (t5_01[0 ] < 0 && t6_01[0 ] >= 0 ) ) {
305- // if diagonal and antidiagonal have different sign, the sign of det is
306- // obvious
307- return det;
308- }
309- RealNumber const magnitude = std::abs (t5_01[0 ]) + std::abs (t6_01[0 ]);
310-
311- // see p.39, mind the different definition of epsilon for error bound
312- RealNumber const A_relative_bound =
313- (1.5 + 4 * std::numeric_limits<RealNumber>::epsilon ())
314- * std::numeric_limits<RealNumber>::epsilon ();
315- RealNumber absolute_bound = A_relative_bound * magnitude;
316- if ( std::abs (det) >= absolute_bound ) {
317- return det; // A estimate
318- }
319-
320288 t5_01[1 ] = two_product_tail (t1[0 ], t2[0 ], t5_01[0 ]);
321289 t6_01[1 ] = two_product_tail (t3[0 ], t4[0 ], t6_01[0 ]);
322290 std::array<RealNumber, 4 > tA_03 = two_two_expansion_diff (t5_01, t6_01);
323- det = std::accumulate (tA_03.begin (), tA_03.end (), static_cast <RealNumber>(0 ));
291+ RealNumber det = std::accumulate (tA_03.begin (), tA_03.end (), static_cast <RealNumber>(0 ));
324292 if (Robustness == 1 ) return det;
325293 // see p.39, mind the different definition of epsilon for error bound
326294 RealNumber B_relative_bound =
327295 (1 + 3 * std::numeric_limits<RealNumber>::epsilon ())
328296 * std::numeric_limits<RealNumber>::epsilon ();
329- absolute_bound = B_relative_bound * magnitude;
330- if (std::abs (det) >= absolute_bound) {
297+ RealNumber absolute_bound = B_relative_bound * magnitude;
298+ if (std::abs (det) >= absolute_bound)
299+ {
331300 return det; // B estimate
332301 }
333- t1[1 ] = two_diff_tail (p1[ 0 ] , p3[ 0 ] , t1[0 ]);
334- t2[1 ] = two_diff_tail (p2[ 1 ] , p3[ 1 ] , t2[0 ]);
335- t3[1 ] = two_diff_tail (p1[ 1 ] , p3[ 1 ] , t3[0 ]);
336- t4[1 ] = two_diff_tail (p2[ 0 ] , p3[ 0 ] , t4[0 ]);
302+ t1[1 ] = two_diff_tail (p1. x , p3. x , t1[0 ]);
303+ t2[1 ] = two_diff_tail (p2. y , p3. y , t2[0 ]);
304+ t3[1 ] = two_diff_tail (p1. y , p3. y , t3[0 ]);
305+ t4[1 ] = two_diff_tail (p2. x , p3. x , t4[0 ]);
337306
338- if ((t1[1 ] == 0 ) && (t3[1 ] == 0 ) && (t2[1 ] == 0 ) && (t4[1 ] == 0 )) {
307+ if ((t1[1 ] == 0 ) && (t3[1 ] == 0 ) && (t2[1 ] == 0 ) && (t4[1 ] == 0 ))
308+ {
339309 return det; // If all tails are zero, there is noething else to compute
340310 }
341311 RealNumber sub_bound =
@@ -348,7 +318,8 @@ inline RealNumber orient2d(std::array<RealNumber, 2> const& p1,
348318 * std::numeric_limits<RealNumber>::epsilon ();
349319 absolute_bound = C_relative_bound * magnitude + sub_bound * std::abs (det);
350320 det += (t1[0 ] * t2[1 ] + t2[0 ] * t1[1 ]) - (t3[0 ] * t4[1 ] + t4[0 ] * t3[1 ]);
351- if (Robustness == 2 || std::abs (det) >= absolute_bound) {
321+ if (Robustness == 2 || std::abs (det) >= absolute_bound)
322+ {
352323 return det; // C estimate
353324 }
354325 std::array<RealNumber, 8 > D_left;
@@ -376,6 +347,50 @@ inline RealNumber orient2d(std::array<RealNumber, 2> const& p1,
376347 return (D[D_nz - 1 ]);
377348}
378349
350+ // see page 38, Figure 21 for the calculations, notation follows the notation in the figure.
351+ template
352+ <
353+ typename RealNumber,
354+ std::size_t Robustness = 3
355+ >
356+ inline RealNumber orient2d (vec2d<RealNumber> const & p1,
357+ vec2d<RealNumber> const & p2,
358+ vec2d<RealNumber> const & p3)
359+ {
360+ if (Robustness == 0 )
361+ {
362+ return (p1.x - p3.x ) * (p2.y - p3.y ) - (p1.y - p3.y ) * (p2.x - p3.x );
363+ }
364+ std::array<RealNumber, 2 > t1, t2, t3, t4;
365+ t1[0 ] = p1.x - p3.x ;
366+ t2[0 ] = p2.y - p3.y ;
367+ t3[0 ] = p1.y - p3.y ;
368+ t4[0 ] = p2.x - p3.x ;
369+ std::array<RealNumber, 2 > t5_01, t6_01;
370+ t5_01[0 ] = t1[0 ] * t2[0 ];
371+ t6_01[0 ] = t3[0 ] * t4[0 ];
372+ RealNumber det = t5_01[0 ] - t6_01[0 ];
373+ RealNumber const magnitude = std::abs (t5_01[0 ]) + std::abs (t6_01[0 ]);
374+
375+ // see p.39, mind the different definition of epsilon for error bound
376+ RealNumber const A_relative_bound =
377+ (1.5 + 4 * std::numeric_limits<RealNumber>::epsilon ())
378+ * std::numeric_limits<RealNumber>::epsilon ();
379+ RealNumber absolute_bound = A_relative_bound * magnitude;
380+ if ( std::abs (det) >= absolute_bound )
381+ {
382+ return det; // A estimate
383+ }
384+
385+ if ( (t5_01[0 ] > 0 && t6_01[0 ] <= 0 ) || (t5_01[0 ] < 0 && t6_01[0 ] >= 0 ) )
386+ {
387+ // if diagonal and antidiagonal have different sign, the sign of det is
388+ // obvious
389+ return det;
390+ }
391+ return orient2dtail<RealNumber, Robustness>(p1, p2, p3, t1, t2, t3, t4, t5_01, t6_01, magnitude);
392+ }
393+
379394// This method adaptively computes increasingly precise approximations of the following
380395// determinant using Laplace expansion along the last column.
381396// det A =
@@ -433,7 +448,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
433448 (5 + 24 * std::numeric_limits<RealNumber>::epsilon ())
434449 * std::numeric_limits<RealNumber>::epsilon ();
435450 RealNumber absolute_bound = A_relative_bound * magnitude;
436- if (std::abs (det) > absolute_bound) {
451+ if (std::abs (det) > absolute_bound)
452+ {
437453 return det;
438454 }
439455 // (p2_x - p4_x) * (p3_y - p4_y)
@@ -492,16 +508,16 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
492508 std::array<RealNumber, 16 > C_23_x_A_22_sq;
493509 // ( (cx - dx) * (ay - dy) - (ax - dx) * (cy - dy) ) * ( by - dy ) * ( by - dy )
494510 int C_23_x_A_22_sq_nz = scale_expansion_zeroelim (C_23_x_A_22, A_22,
495- C_23_x_A_22_sq,
496- C_23_x_A_22_nz);
511+ C_23_x_A_22_sq,
512+ C_23_x_A_22_nz);
497513 std::array<RealNumber, 32 > A_23_x_C_23;
498- // ( (cx - dx) * (ay - dy) - (ax - dx) * (cy - dy) )
499- // * ( ( bx - dx ) * ( bx - dx ) + ( by - dy ) * ( by - dy ) )
514+ // ( (cx - dx) * (ay - dy) - (ax - dx) * (cy - dy) )
515+ // * ( ( bx - dx ) * ( bx - dx ) + ( by - dy ) * ( by - dy ) )
500516 int A_23_x_C_23_nz = fast_expansion_sum_zeroelim (C_23_x_A_21_sq,
501- C_23_x_A_22_sq,
502- A_23_x_C_23,
503- C_23_x_A_21_sq_nz,
504- C_23_x_A_22_sq_nz);
517+ C_23_x_A_22_sq,
518+ A_23_x_C_23,
519+ C_23_x_A_21_sq_nz,
520+ C_23_x_A_22_sq_nz);
505521
506522 // (ax - dx) * (by - dy)
507523 A_11_x_A_22[1 ] = two_product_tail (A_11, A_22, A_11_x_A_22[0 ]);
@@ -555,7 +571,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
555571 (2 + 12 * std::numeric_limits<RealNumber>::epsilon ())
556572 * std::numeric_limits<RealNumber>::epsilon ();
557573 absolute_bound = B_relative_bound * magnitude;
558- if (std::abs (det) >= absolute_bound) {
574+ if (std::abs (det) >= absolute_bound)
575+ {
559576 return det;
560577 }
561578 RealNumber A_11tail = two_diff_tail (p1[0 ], p4[0 ], A_11);
@@ -565,7 +582,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
565582 RealNumber A_31tail = two_diff_tail (p3[0 ], p4[0 ], A_31);
566583 RealNumber A_32tail = two_diff_tail (p3[1 ], p4[1 ], A_32);
567584 if ((A_11tail == 0 ) && (A_21tail == 0 ) && (A_31tail == 0 )
568- && (A_12tail == 0 ) && (A_22tail == 0 ) && (A_32tail == 0 )) {
585+ && (A_12tail == 0 ) && (A_22tail == 0 ) && (A_32tail == 0 ))
586+ {
569587 return det;
570588 }
571589 // RealNumber sub_bound = (1.5 + 2.0 * std::numeric_limits<RealNumber>::epsilon())
@@ -583,7 +601,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
583601 + ((A_31 * A_31 + A_32 * A_32) * ((A_11 * A_22tail + A_22 * A_11tail)
584602 - (A_12 * A_21tail + A_21 * A_12tail))
585603 + 2 * (A_31 * A_31tail + A_32 * A_32tail) * (A_11 * A_22 - A_12 * A_21));
586- // if (std::abs(det) >= absolute_bound) {
604+ // if (std::abs(det) >= absolute_bound)
605+ // {
587606 return det;
588607 // }
589608}
0 commit comments