├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── lib.rs ├── predicates.c ├── predicates.rs ├── transpiled.rs └── transpiled └── c2rust.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | - name: Run tests with all features 24 | run: cargo test --all-features --verbose 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - nightly 5 | - beta 6 | - stable 7 | 8 | cache: cargo 9 | 10 | env: 11 | - CARGO_FEATURES="" 12 | 13 | matrix: 14 | include: 15 | - rust: nightly 16 | env: CARGO_FEATURES="unstable" 17 | 18 | script: 19 | - cargo build --features "$CARGO_FEATURES" 20 | - cargo test --features "$CARGO_FEATURES" 21 | - cargo miri test --features "$CARGO_FEATURES" 22 | - | 23 | if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then 24 | cargo bench --features "$CARGO_FEATURES" 25 | fi 26 | 27 | notifications: 28 | email: false 29 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geometry-predicates" 3 | version = "0.3.0" 4 | authors = ["Egor Larionov "] 5 | license = "MIT" 6 | description = "A Rust port of robust geometric predicates" 7 | 8 | homepage = "https://github.com/elrnv/geometry-predicates-rs" 9 | repository = "https://github.com/elrnv/geometry-predicates-rs" 10 | readme = "README.md" 11 | 12 | keywords = ["geometry", "predicate", "robust", "exact", "arithmetic"] 13 | 14 | categories = ["algorithms"] 15 | 16 | [badges] 17 | travis-ci = { repository = "elrnv/geometry-predicates-rs", branch = "master" } 18 | 19 | [features] 20 | unstable = [] 21 | transpiled = [] 22 | 23 | [dependencies] 24 | 25 | [dev-dependencies] 26 | rand = "0.3" 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Egor Larionov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # geometry-predicates 2 | 3 | A safe Rust port of ["Adaptive Precision Floating-Point Arithmetic and Fast Robust 4 | Predicates for Computational Geometry"](https://www.cs.cmu.edu/~quake/robust.html) 5 | 6 | [![Build Status](https://github.com/elrnv/geometry-predicates-rs/workflows/Test/badge.svg)](https://github.com/elrnv/geometry-predicates-rs/actions) 7 | [![Documentation](https://docs.rs/geometry-predicates/badge.svg)](https://docs.rs/geometry-predicates) 8 | [![Version](https://img.shields.io/crates/v/geometry-predicates.svg)](https://crates.io/crates/geometry-predicates) 9 | [![License](https://img.shields.io/crates/l/geometry-predicates.svg)](https://github.com/elrnv/geometry-predicates-rs/blob/master/LICENSE) 10 | [![Downloads](https://img.shields.io/crates/d/geometry-predicates.svg)](https://crates.io/crates/geometry-predicates) 11 | 12 | This library provides a Rust solution to efficient exact geometry predicates 13 | used widely for computational geometry. 14 | 15 | The following predicates are exposed at the root level: 16 | - orient2d 17 | - incircle 18 | - orient3d 19 | - insphere 20 | 21 | Along with their approximate (inexact) counterparts: 22 | - orient2d_fast 23 | - incircle_fast 24 | - orient3d_fast 25 | - insphere_fast 26 | 27 | In addition, the building blocks of these predicates, namely the adaptive precision 28 | floating-point arithmetic primitives are also exposed to allow for extensions to 29 | other predicates or exact geometric constructions. 30 | 31 | This library supports `no-std` targets with standard IEEE 754 floats. 32 | 33 | 34 | ## Background 35 | 36 | These predicates have been a staple in computational geometry for many years now 37 | and are widely used in industry. In the context of geometry algorithms, it is 38 | often essential to determine the orientation of a point with respect to a line (or a 39 | plane) and whether a point lies inside a circle (or a sphere) or not. The reason 40 | why these tests often need to be exact is because many geometry algorithms 41 | ask questions (to determine orientation or in-circle/sphere) about point 42 | configurations that require consistent answers. For instance, if `a`, `b`, and 43 | `c` are three points on a 2D plane, to ask where `b` with respect to the line 44 | through `a` and `c` (left-of, right-of, or coincident) is the same as asking where 45 | `a` lies with respect to the line through `c` and `b`. 46 | Formally this condition can be written as 47 | ``` 48 | sgn(orient2d(a,c,b)) == sgn(orient2d(c,b,a)) 49 | ``` 50 | 51 | Mathematically, predicates like `orient2d` are 52 | defined as 53 | ``` 54 | ⎛⎡ax ay 1⎤⎞ 55 | orient2d([ax,ay],[bx,by],[cx,cy]) := det⎜⎢bx by 1⎥⎟ 56 | ⎝⎣cx cy 1⎦⎠ 57 | ``` 58 | 59 | It's easy to see that these predicates solve the problem of 60 | computing the determinant of small matrices with the correct sign, regardless of how 61 | close the matrix is to being singular. 62 | 63 | For instance to compute the determinant of a matrix `[a b; c d]` with the 64 | correct sign, we can invoke 65 | ``` 66 | orient2d([a,b], [c,d], [0,0]) 67 | ``` 68 | 69 | For more details please refer to Jonathan Shewchuk's [original 70 | webpage](https://www.cs.cmu.edu/~quake/robust.html) for these predicates. 71 | 72 | 73 | ## Caveats 74 | 75 | These predicates do NOT handle exponent overflow [\[1\]], which means inputs with floats smaller than 76 | `1e-142` or larger than `1e201` may not produce accurate results. This is true for the original 77 | predicates in `predicates.c` as well as other Rust ports and bindings for these predicates. 78 | 79 | 80 | ## References 81 | 82 | - [\[1\] Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates][\[1\]], 83 | Discrete & Computational Geometry 18(3):305–363, October 1997. 84 | - [\[2\] Robust Adaptive Floating-Point Geometric Predicates Proceedings of the Twelfth Annual][\[2\]], 85 | Symposium on Computational Geometry (Philadelphia, Pennsylvania), pages 141–150, Association for 86 | Computing Machinery, May 1996 87 | 88 | 89 | ## Acknowledgements 90 | 91 | This port was originally created by a C to Rust translator called 92 | [Corrode](https://github.com/jameysharp/corrode). Without it, a full Rust port 93 | of this library would have been a daunting task. With that I would specifically like to thank the 94 | authors of Corrode for providing such a useful tool. 95 | Version 0.2 of this crate used the [c2rust](https://c2rust.com/) crate. The same gratitude goes towards 96 | the developers of C2Rust. 97 | 98 | [\[1\]]: http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf 99 | [\[2\]]: http://www.cs.berkeley.edu/~jrs/papers/robust-predicates.pdf 100 | 101 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A safe Rust port of the [robust adaptive floating-point geometric predicates](https://www.cs.cmu.edu/~quake/robust.html). 2 | //! 3 | //! This crate provides a Rust solution to efficient exact geometry predicates 4 | //! used widely for computational geometry. 5 | //! 6 | //! In addition, the building blocks of these predicates, namely the adaptive precision 7 | //! floating-point arithmetic primitives, are also exposed in [`predicates`] to allow for extensions 8 | //! to other predicates or exact geometric constructions. 9 | //! 10 | //! ## Background 11 | //! 12 | //! These predicates have been a staple in computational geometry for many years now 13 | //! and are widely used in industry. In the context of geometry algorithms, it is 14 | //! often essential to determine the orientation of a point with respect to a line (or a 15 | //! plane) and whether a point lies inside a circle (or a sphere) or not. The reason 16 | //! why these tests often need to be exact is because many geometry algorithms 17 | //! ask questions (to determine orientation or in-circle/sphere) about point 18 | //! configurations that require consistent answers. For instance, if `a`, `b`, and 19 | //! `c` are three points on a 2D plane, to ask where `b` with respect to the line 20 | //! through `a` and `c` (left-of, right-of, or coincident) is the same as asking where 21 | //! `a` lies with respect to the line through `c` and `b`. 22 | //! In Rust, this condition can be written as 23 | //! ``` 24 | //! # use geometry_predicates::orient2d; 25 | //! # let a = [1.0, 2.0]; 26 | //! # let b = [3.0, 4.0]; 27 | //! # let c = [5.0, 6.0]; 28 | //! assert_eq!(orient2d(a,c,b).signum(), orient2d(c,b,a).signum()); 29 | //! ``` 30 | //! 31 | //! Mathematically, predicates like `orient2d` are 32 | //! defined as 33 | //!```verbatim 34 | //! ⎛⎡ax ay 1⎤⎞ 35 | //!orient2d([ax,ay],[bx,by],[cx,cy]) := det⎜⎢bx by 1⎥⎟ 36 | //! ⎝⎣cx cy 1⎦⎠ 37 | //!``` 38 | //! 39 | //! It's easy to see that these predicates solve the problem of 40 | //! computing the determinant of small matrices with the correct sign, regardless of how 41 | //! close the matrix is to being singular. 42 | //! 43 | //! For instance to compute the determinant of a matrix `[a b; c d]` with the 44 | //! correct sign, we can invoke 45 | //! ``` 46 | //! # use geometry_predicates::orient2d; 47 | //! # let a = 1.0; 48 | //! # let b = 2.0; 49 | //! # let c = 3.0; 50 | //! # let d = 4.0; 51 | //! assert_eq!(orient2d([a,b], [c,d], [0.0,0.0]), a*d - b*c); 52 | //! ``` 53 | //! 54 | //! For more details please refer to the [original 55 | //! webpage](https://www.cs.cmu.edu/~quake/robust.html) for these predicates. 56 | //! 57 | //! ## Caveats 58 | //! 59 | //! These predicates do NOT handle exponent overflow [\[1\]], which means inputs with floats smaller than 60 | //! `1e-142` or larger than `1e201` may not produce accurate results. This is true for the original 61 | //! predicates in `predicates.c` as well as other Rust ports and bindings for these predicates. 62 | //! 63 | //! ## References 64 | //! 65 | //! - [\[1\] Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates][\[1\]], 66 | //! Discrete & Computational Geometry 18(3):305–363, October 1997. 67 | //! - [\[2\] Robust Adaptive Floating-Point Geometric Predicates Proceedings of the Twelfth Annual][\[2\]], 68 | //! Symposium on Computational Geometry (Philadelphia, Pennsylvania), pages 141–150, Association for 69 | //! Computing Machinery, May 1996 70 | //! 71 | //! [\[1\]]: http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf 72 | //! [\[2\]]: http://www.cs.berkeley.edu/~jrs/papers/robust-predicates.pdf 73 | #![no_std] 74 | pub mod predicates; 75 | 76 | #[cfg(feature = "transpiled")] 77 | mod transpiled; 78 | 79 | // The following predicates are exposed at the top level. 80 | // There are other alternative robust implementations (but typically slower) of these predicates. 81 | // We use those to check the adaptive implementations. 82 | pub use predicates::{ 83 | // Adaptive robust predicates. 84 | incircle, 85 | // Fast inexact predicates. 86 | incircle_fast, 87 | insphere, 88 | insphere_fast, 89 | orient2d, 90 | orient2d_fast, 91 | orient3d, 92 | orient3d_fast, 93 | }; 94 | 95 | #[cfg(test)] 96 | mod tests { 97 | extern crate rand; 98 | use self::rand::{Rng, SeedableRng, StdRng}; 99 | use super::*; 100 | 101 | use predicates::{ 102 | incircle_exact, incircle_slow, insphere_exact, insphere_slow, orient2d_exact, 103 | orient2d_slow, orient3d_exact, orient3d_slow, 104 | }; 105 | 106 | const SEED: &[usize] = &[1, 2, 3, 4]; 107 | 108 | /* 109 | * Note on robustness testing. 110 | * 111 | * These predicates do NOT handle overflow or underflowo of the exponent. 112 | * Quoting Shechuk's predicates paper directly: 113 | * 114 | * > The four predicates implemented [in this library] will not overflow nor underflow if their 115 | * > inputs have exponents in the range [-142, 201] and IEEE 754 double precision arithmetic 116 | * > is used. 117 | * - Jonathan Shechuk 1997 118 | * 119 | * We will therefore be careful to test for inputs with exponents in that range and not beyond. 120 | */ 121 | 122 | const EXP_BOUNDS: [i32; 2] = [-142, 201]; 123 | 124 | /// Generate a tolerance value with exponent no less than -142. 125 | fn tol(rng: &mut StdRng) -> f64 { 126 | let max_exp = (EXP_BOUNDS[0] + 1) as f64; 127 | 10.0_f64.powi((max_exp * rng.gen::()).round() as i32) * (rng.gen::() - 0.5) 128 | } 129 | 130 | /* 131 | * Many of the tests below ensure that the predicates produce expected results for all 132 | * permutations of the inputs. Thus, below we write an adhoc QuickPerm implementation to 133 | * generate swap based permutations. 134 | * 135 | * The following is a basic countdown implementation of QuickPerm (see quickperm.org). 136 | * This implementation can be refactored to use const generics when those stabilize. 137 | */ 138 | macro_rules! quick_perm_impl { 139 | ($n:expr, $struct_name:ident) => { 140 | struct $struct_name { 141 | perm: [T; $n], 142 | p: [usize; $n + 1], 143 | index: usize, 144 | } 145 | 146 | impl $struct_name { 147 | fn new(v: [T; $n]) -> Self { 148 | let mut p = [0; $n + 1]; 149 | for i in 0..$n + 1 { 150 | p[i] = i; 151 | } 152 | $struct_name { 153 | perm: v, 154 | p, 155 | index: 0, 156 | } 157 | } 158 | } 159 | 160 | impl Iterator for $struct_name { 161 | type Item = [T; $n]; 162 | fn next(&mut self) -> Option { 163 | let $struct_name { perm, p, index } = self; 164 | let mut i = *index; 165 | let n = p.len() - 1; 166 | if i == 0 { 167 | *index += 1; 168 | return Some(perm.clone()); 169 | } else if i >= n { 170 | return None; 171 | } 172 | p[i] -= 1; 173 | let j = if i % 2 == 0 { 0 } else { p[i] }; 174 | perm.swap(j, i); 175 | i = 1; 176 | while p[i] == 0 { 177 | p[i] = i; 178 | i += 1; 179 | } 180 | *index = i; 181 | Some(perm.clone()) 182 | } 183 | } 184 | }; 185 | } 186 | 187 | quick_perm_impl!(3, QuickPerm3); 188 | quick_perm_impl!(4, QuickPerm4); 189 | quick_perm_impl!(5, QuickPerm5); 190 | 191 | /* 192 | * The tests below have specific purposes. 193 | * 194 | * - _robustness_ tests check that the adaptive predicates work in degenerate or close to degenerate 195 | * configurations 196 | * - _regression_ tests verify the adpative predicates against their _slow and _exact variants. 197 | * - _transpiled_regression_ tests verify the predicates against the directly transpiled 198 | * (unrefactored) version of the library. 199 | */ 200 | 201 | #[test] 202 | fn orient2d_test() { 203 | let a = [0.0, 1.0]; 204 | let b = [2.0, 3.0]; 205 | let c = [4.0, 5.0]; 206 | assert_eq!(orient2d(a, b, c), 0.0); 207 | } 208 | 209 | #[cfg(feature = "transpiled")] 210 | #[test] 211 | fn orient2d_transpiled_regression_test() { 212 | unsafe { 213 | transpiled::exactinit(); 214 | } 215 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 216 | 217 | let n = 99999; 218 | for _ in 0..n { 219 | let a = [tol(&mut rng), tol(&mut rng)]; 220 | let b = [12.0, 12.0]; 221 | let c = [24.0, 24.0]; 222 | let o2d = orient2d; 223 | let o2d_transpiled = transpiled::orient2d; 224 | for p in QuickPerm3::new([a, b, c]) { 225 | assert_eq!( 226 | o2d(p[0], p[1], p[2]), 227 | o2d_transpiled(p[0], p[1], p[2]), 228 | "{:?}", 229 | a 230 | ); 231 | } 232 | } 233 | } 234 | 235 | #[test] 236 | fn orient2d_robustness_test() { 237 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 238 | let n = 99999; 239 | 240 | for o2d in &[orient2d, orient2d_exact, orient2d_slow] { 241 | for _ in 0..n { 242 | let pa = [tol(&mut rng), tol(&mut rng)]; 243 | let pb = [12.0, 12.0]; 244 | let pc = [24.0, 24.0]; 245 | 246 | let main = o2d(pa, pb, pc); 247 | if main == 0.0 { 248 | for [a, b, c] in QuickPerm3::new([pa, pb, pc]) { 249 | assert_eq!(o2d(a, b, c), 0.0); 250 | } 251 | } 252 | 253 | let pred = main > 0.0; 254 | for (i, [a, b, c]) in QuickPerm3::new([pa, pb, pc]).enumerate() { 255 | let t = o2d(a, b, c); 256 | assert_eq!(pred, if i % 2 == 0 { t > 0.0 } else { t < 0.0 }); 257 | } 258 | } 259 | } 260 | } 261 | 262 | // The following test verifies equivalence of all of the robust orient2d variants (including 263 | // exact and slow variants). 264 | #[test] 265 | fn orient2d_regression_test() { 266 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 267 | 268 | let n = 99999; 269 | for _ in 0..n { 270 | let pa = [tol(&mut rng), tol(&mut rng)]; 271 | let pb = [12.0, 12.0]; 272 | let pc = [24.0, 24.0]; 273 | 274 | let o2d = predicates::orient2d; 275 | let o2de = predicates::orient2d_exact; 276 | let o2ds = predicates::orient2d_slow; 277 | 278 | // Test all permutations. 279 | 280 | for [a, b, c] in QuickPerm3::new([pa, pb, pc]) { 281 | assert_eq!( 282 | o2d(a, b, c).partial_cmp(&0.0), 283 | o2de(a, b, c).partial_cmp(&0.0), 284 | "{:?}", 285 | pa 286 | ); 287 | assert_eq!( 288 | o2d(a, b, c).partial_cmp(&0.0), 289 | o2ds(a, b, c).partial_cmp(&0.0), 290 | "{:?}", 291 | pa 292 | ); 293 | } 294 | } 295 | } 296 | 297 | #[test] 298 | fn orient2d_fast_test() { 299 | let a = [0.0, 1.0]; 300 | let b = [2.0, 3.0]; 301 | let c = [4.0, 5.0]; 302 | assert_eq!(orient2d_fast(a, b, c), 0.0); 303 | 304 | // The fast orientation test should also work when the given points are sufficiently 305 | // non-colinear. 306 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 307 | let tol = 5.0e-10; // will not work with 5.0e-14 308 | 309 | for _ in 0..999 { 310 | let a = [0.5 + tol * rng.gen::(), 0.5 + tol * rng.gen::()]; 311 | let b = [12.0, 12.0]; 312 | let c = [24.0, 24.0]; 313 | assert_eq!(orient2d_fast(a, b, c) > 0.0, orient2d_fast(b, c, a) > 0.0); 314 | assert_eq!(orient2d_fast(b, c, a) > 0.0, orient2d_fast(c, a, b) > 0.0); 315 | assert_eq!(orient2d_fast(a, b, c) > 0.0, orient2d_fast(b, a, c) < 0.0); 316 | assert_eq!(orient2d_fast(a, b, c) > 0.0, orient2d_fast(a, c, b) < 0.0); 317 | } 318 | } 319 | 320 | #[test] 321 | fn orient3d_test() { 322 | let a = [0.0, 1.0, 6.0]; 323 | let b = [2.0, 3.0, 4.0]; 324 | let c = [4.0, 5.0, 1.0]; 325 | let d = [6.0, 2.0, 5.3]; 326 | assert_eq!(orient3d(a, b, c, d), 10.0); 327 | } 328 | 329 | #[cfg(feature = "transpiled")] 330 | #[test] 331 | fn orient3d_transpiled_regression_test() { 332 | unsafe { 333 | transpiled::exactinit(); 334 | } 335 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 336 | 337 | let n = 9999; 338 | for _ in 0..n { 339 | let pa = [tol(&mut rng), tol(&mut rng), tol(&mut rng)]; 340 | let pb = [12.0, 12.0, 12.0]; 341 | let pc = [24.0, 24.0, 24.0]; 342 | let pd = [48.0, 48.0, 48.0]; 343 | 344 | let o3d = predicates::orient3d; 345 | let o3d_transpiled = transpiled::orient3d; 346 | 347 | // Test all permutations. 348 | for [a, b, c, d] in QuickPerm4::new([pa, pb, pc, pd]) { 349 | assert_eq!(o3d(a, c, d, b), o3d_transpiled(a, c, d, b), "{:?}", pa); 350 | } 351 | } 352 | } 353 | 354 | // The following test verifies equivalence of all of the robust orient3d variants. 355 | #[test] 356 | fn orient3d_regression_test() { 357 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 358 | 359 | let n = 5000; 360 | for _ in 0..n { 361 | let pa = [tol(&mut rng), tol(&mut rng), tol(&mut rng)]; 362 | let pb = [12.0, 12.0, 12.0]; 363 | let pc = [24.0, 24.0, 24.0]; 364 | let pd = [48.0, 48.0, 48.0]; 365 | 366 | let o3d = predicates::orient3d; 367 | let o3de = predicates::orient3d_exact; 368 | let o3ds = predicates::orient3d_slow; 369 | 370 | // Test all permutations. 371 | // Actually these don't need to be exactly equal, they just need to compare equally to 372 | // 0.0. It just so happens that they are also equal. 373 | for [a, b, c, d] in QuickPerm4::new([pa, pb, pc, pd]) { 374 | assert_eq!(o3d(a, c, d, b), o3de(a, c, d, b), "{:?}", pa); 375 | assert_eq!(o3d(a, c, d, b), o3ds(a, c, d, b), "{:?}", pa); 376 | } 377 | } 378 | } 379 | 380 | #[test] 381 | fn orient3d_robustness_test() { 382 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 383 | 384 | let n = 999; 385 | 386 | for o3d in &[orient3d, orient3d_exact, orient3d_slow] { 387 | for _ in 0..n { 388 | let pa = [tol(&mut rng), tol(&mut rng), tol(&mut rng)]; 389 | let pb = [12.0, 12.0, 12.0]; 390 | let pc = [24.0, 24.0, 24.0]; 391 | let pd = [48.0, 48.0, 48.0]; 392 | 393 | // Test all permutations. 394 | 395 | let main = o3d(pa, pb, pc, pd); 396 | 397 | if main == 0.0 { 398 | for [a, b, c, d] in QuickPerm4::new([pa, pb, pc, pd]) { 399 | assert_eq!(o3d(a, b, c, d), 0.0); 400 | } 401 | } 402 | 403 | let pred = main > 0.0; 404 | for (i, [a, b, c, d]) in QuickPerm4::new([pa, pb, pc, pd]).enumerate() { 405 | let t = o3d(a, b, c, d); 406 | assert_eq!( 407 | pred, 408 | if i % 2 == 0 { t > 0.0 } else { t < 0.0 }, 409 | "{} vs. {} at {:?}", 410 | t, 411 | -main, 412 | pa 413 | ); 414 | } 415 | } 416 | } 417 | } 418 | 419 | #[test] 420 | fn orient3d_fast_test() { 421 | let a = [0.0, 1.0, 6.0]; 422 | let b = [2.0, 3.0, 4.0]; 423 | let c = [4.0, 5.0, 1.0]; 424 | let d = [6.0, 2.0, 5.3]; 425 | assert!(f64::abs(orient3d_fast(a, b, c, d) - 10.0) < 1.0e-4); 426 | 427 | // The fast orientation test should also work when the given points are sufficiently 428 | // non-colinear. 429 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 430 | let tol = 5.0; 431 | 432 | let a = [ 433 | 0.5 + tol * rng.gen::(), 434 | 0.5 + tol * rng.gen::(), 435 | 0.5 + tol * rng.gen::(), 436 | ]; 437 | let b = [12.0, 12.0, 12.0]; 438 | let c = [24.0, 24.0, 24.0]; 439 | let d = [48.0, 48.0, 48.0]; 440 | assert_eq!( 441 | orient3d_fast(a, b, c, d) > 0.0, 442 | orient3d_fast(b, c, a, d) > 0.0 443 | ); 444 | assert_eq!( 445 | orient3d_fast(b, a, c, d) < 0.0, 446 | orient3d_fast(c, b, d, a) < 0.0 447 | ); 448 | // The following orientations are expected to be inconsistent 449 | // (this is why we need exact predicates) 450 | assert_ne!( 451 | orient3d_fast(b, c, d, a) > 0.0, 452 | orient3d_fast(c, d, a, b) > 0.0 453 | ); 454 | assert_ne!( 455 | orient3d_fast(b, d, c, a) < 0.0, 456 | orient3d_fast(c, d, b, a) < 0.0 457 | ); 458 | } 459 | 460 | #[test] 461 | fn incircle_test() { 462 | let a = [0.0, 1.0]; 463 | let b = [1.0, 0.0]; 464 | let c = [1.0, 1.0]; 465 | let d = [0.0, 0.0]; 466 | assert_eq!(incircle(a, b, c, d), 0.0); 467 | let d = [0.1, 0.1]; 468 | assert!(incircle(a, b, c, d) > 0.0); 469 | let d = [-0.1, -0.1]; 470 | assert!(incircle(a, b, c, d) < 0.0); 471 | } 472 | 473 | #[test] 474 | fn incircle_robustness_test() { 475 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 476 | 477 | let n = 999; 478 | for ic in &[incircle, incircle_exact, incircle_slow] { 479 | for _ in 0..n { 480 | let pa = [0.0, 1.0]; 481 | let pb = [1.0, 0.0]; 482 | let pc = [1.0, 1.0]; 483 | let pd = [tol(&mut rng), tol(&mut rng)]; 484 | 485 | let main = ic(pa, pb, pc, pd); 486 | 487 | if main == 0.0 { 488 | for [a, b, c, d] in QuickPerm4::new([pa, pb, pc, pd]) { 489 | assert_eq!(ic(a, b, c, d), 0.0); 490 | } 491 | } 492 | 493 | let pred = main > 0.0; 494 | for (i, [a, b, c, d]) in QuickPerm4::new([pa, pb, pc, pd]).enumerate() { 495 | let t = ic(a, b, c, d); 496 | assert_eq!( 497 | pred, 498 | if i % 2 == 0 { t > 0.0 } else { t < 0.0 }, 499 | "{} vs. {} at {:?}", 500 | t, 501 | -main, 502 | pd 503 | ); 504 | } 505 | } 506 | } 507 | } 508 | 509 | #[test] 510 | fn insphere_test() { 511 | let a = [0.0, 1.0, 0.0]; 512 | let b = [1.0, 0.0, 0.0]; 513 | let c = [0.0, 0.0, 1.0]; 514 | let d = [1.0, 1.0, 1.0]; 515 | let e = [0.0, 0.0, 0.0]; 516 | assert_eq!(insphere(a, b, c, d, e), 0.0); 517 | let e = [0.1, 0.1, 0.1]; 518 | assert!(insphere(a, b, c, d, e) > 0.0); 519 | let e = [-0.1, -0.1, -0.1]; 520 | assert!(insphere(a, b, c, d, e) < 0.0); 521 | } 522 | 523 | #[test] 524 | fn insphere_robustness_test() { 525 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 526 | 527 | let n = 99; 528 | for is in &[insphere, insphere_exact, insphere_slow] { 529 | for _ in 0..n { 530 | let pa = [0.0, 1.0, 0.0]; 531 | let pb = [1.0, 0.0, 0.0]; 532 | let pc = [0.0, 0.0, 1.0]; 533 | let pd = [1.0, 1.0, 1.0]; 534 | let pe = [tol(&mut rng), tol(&mut rng), tol(&mut rng)]; 535 | 536 | let main = is(pa, pb, pc, pd, pe); 537 | 538 | if main == 0.0 { 539 | for [a, b, c, d, e] in QuickPerm5::new([pa, pb, pc, pd, pe]) { 540 | assert_eq!(is(a, b, c, d, e), 0.0); 541 | } 542 | } 543 | 544 | let pred = main > 0.0; 545 | for (i, [a, b, c, d, e]) in QuickPerm5::new([pa, pb, pc, pd, pe]).enumerate() { 546 | let t = is(a, b, c, d, e); 547 | assert_eq!( 548 | pred, 549 | if i % 2 == 0 { t > 0.0 } else { t < 0.0 }, 550 | "{} vs. {} at {:?}", 551 | t, 552 | -main, 553 | pe 554 | ); 555 | } 556 | } 557 | } 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /src/predicates.rs: -------------------------------------------------------------------------------- 1 | /// Returns the absolute value of the given number. 2 | /// 3 | /// This function exists since [`std::f64::abs`](std::f64::abs) is not available in core. 4 | /// See [#50145](https://github.com/rust-lang/rust/issues/50145) 5 | /// 6 | /// This implementation is identical to [`std::f64::abs`](std::f64::abs) on x86 but not on ARM at the time of this writing. 7 | #[inline] 8 | pub fn abs(a: f64) -> f64 { 9 | f64::from_bits(a.to_bits() & 0x7FFF_FFFF_FFFF_FFFF) 10 | } 11 | 12 | #[derive(Debug)] 13 | struct PredicateParams { 14 | // Used to split floats in half. 15 | splitter: f64, // = 2^ceiling(p / 2) + 1. 16 | /* A set of coefficients used to calculate maximum roundoff errors. */ 17 | resulterrbound: f64, 18 | ccwerrbound_a: f64, 19 | ccwerrbound_b: f64, 20 | ccwerrbound_c: f64, 21 | o3derrbound_a: f64, 22 | o3derrbound_b: f64, 23 | o3derrbound_c: f64, 24 | iccerrbound_a: f64, 25 | iccerrbound_b: f64, 26 | iccerrbound_c: f64, 27 | isperrbound_a: f64, 28 | isperrbound_b: f64, 29 | isperrbound_c: f64, 30 | } 31 | 32 | // EPSILON and PARAMS.slitter were pregenerated using exactinit on a machine with IEEE 754 floats. 33 | // See `exactinit` function below for details. 34 | 35 | /// The largest power of two such that 1.0 + epsilon = 1.0 in floating-point 36 | /// arithmetic. 37 | /// 38 | /// This number bounds the relative roundoff error. It is used for 39 | /// floating-point error analysis. 40 | const EPSILON: f64 = 0.000_000_000_000_000_111_022_302_462_515_65; 41 | 42 | /// Constants used in exact arithmetic. 43 | /// 44 | /// See exactinit() for the function used to generate these values. 45 | const PARAMS: PredicateParams = PredicateParams { 46 | /// Used to split floating-point numbers into two half-length significands 47 | /// for exact multiplication. 48 | splitter: 134_217_729f64, 49 | resulterrbound: (3.0 + 8.0 * EPSILON) * EPSILON, 50 | ccwerrbound_a: (3.0 + 16.0 * EPSILON) * EPSILON, 51 | ccwerrbound_b: (2.0 + 12.0 * EPSILON) * EPSILON, 52 | ccwerrbound_c: (9.0 + 64.0 * EPSILON) * EPSILON * EPSILON, 53 | o3derrbound_a: (7.0f64 + 56.0f64 * EPSILON) * EPSILON, 54 | o3derrbound_b: (3.0f64 + 28.0f64 * EPSILON) * EPSILON, 55 | o3derrbound_c: (26.0f64 + 288.0f64 * EPSILON) * EPSILON * EPSILON, 56 | iccerrbound_a: (10.0 + 96.0 * EPSILON) * EPSILON, 57 | iccerrbound_b: (4.0 + 48.0 * EPSILON) * EPSILON, 58 | iccerrbound_c: (44.0 + 576.0 * EPSILON) * EPSILON * EPSILON, 59 | isperrbound_a: (16.0f64 + 224.0f64 * EPSILON) * EPSILON, 60 | isperrbound_b: (5.0f64 + 72.0f64 * EPSILON) * EPSILON, 61 | isperrbound_c: (71.0f64 + 1408.0f64 * EPSILON) * EPSILON * EPSILON, 62 | }; 63 | 64 | /* ****************************************************************************/ 65 | /* */ 66 | /* exactinit() Initialize the variables used for exact arithmetic. */ 67 | /* */ 68 | /* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ 69 | /* floating-point arithmetic. `epsilon' bounds the relative roundoff */ 70 | /* error. It is used for floating-point error analysis. */ 71 | /* */ 72 | /* `splitter' is used to split floating-point numbers into two half- */ 73 | /* length significands for exact multiplication. */ 74 | /* */ 75 | /* I imagine that a highly optimizing compiler might be too smart for its */ 76 | /* own good, and somehow cause this routine to fail, if it pretends that */ 77 | /* floating-point arithmetic is too much like real arithmetic. */ 78 | /* */ 79 | /* Don't change this routine unless you fully understand it. */ 80 | /* */ 81 | /* ****************************************************************************/ 82 | #[allow(dead_code)] // This function is for reference only. 83 | fn exactinit() -> PredicateParams { 84 | let mut check = 1.0_f64; 85 | let mut lastcheck; 86 | let mut every_other = 1_i32; 87 | let mut epsilon = 1.0f64; 88 | let mut splitter = 1.0f64; 89 | loop { 90 | /* Repeatedly divide `epsilon' by two until it is too small to add to */ 91 | /* one without causing roundoff. (Also check if the sum is equal to */ 92 | /* the previous sum, for machines that round up instead of using exact */ 93 | /* rounding. Not that this library will work on such machines anyway. */ 94 | lastcheck = check; 95 | epsilon *= 0.5; 96 | if every_other != 0 { 97 | splitter *= 2.0f64 98 | } 99 | every_other = (every_other == 0) as i32; 100 | check = 1.0f64 + epsilon; 101 | if !(check != 1.0f64 && check != lastcheck) { 102 | break; 103 | } 104 | } 105 | splitter += 1.0f64; 106 | PredicateParams { 107 | splitter, 108 | /* Error bounds for orientation and incircle tests. */ 109 | resulterrbound: (3.0f64 + 8.0f64 * epsilon) * epsilon, 110 | ccwerrbound_a: (3.0f64 + 16.0f64 * epsilon) * epsilon, 111 | ccwerrbound_b: (2.0f64 + 12.0f64 * epsilon) * epsilon, 112 | ccwerrbound_c: (9.0f64 + 64.0f64 * epsilon) * epsilon * epsilon, 113 | o3derrbound_a: (7.0f64 + 56.0f64 * epsilon) * epsilon, 114 | o3derrbound_b: (3.0f64 + 28.0f64 * epsilon) * epsilon, 115 | o3derrbound_c: (26.0f64 + 288.0f64 * epsilon) * epsilon * epsilon, 116 | iccerrbound_a: (10.0f64 + 96.0f64 * epsilon) * epsilon, 117 | iccerrbound_b: (4.0f64 + 48.0f64 * epsilon) * epsilon, 118 | iccerrbound_c: (44.0f64 + 576.0f64 * epsilon) * epsilon * epsilon, 119 | isperrbound_a: (16.0f64 + 224.0f64 * epsilon) * epsilon, 120 | isperrbound_b: (5.0f64 + 72.0f64 * epsilon) * epsilon, 121 | isperrbound_c: (71.0f64 + 1408.0f64 * epsilon) * epsilon * epsilon, 122 | } 123 | } 124 | 125 | /* Many of the operations are broken up into two pieces, a main part that */ 126 | /* performs an approximate operation, and a "tail" that computes the */ 127 | /* roundoff error of that operation. */ 128 | 129 | #[inline] 130 | pub fn fast_two_sum_tail(a: f64, b: f64, x: f64) -> f64 { 131 | let bvirt: f64 = x - a; 132 | b - bvirt 133 | } 134 | 135 | #[inline] 136 | pub fn fast_two_sum(a: f64, b: f64) -> [f64; 2] { 137 | let x: f64 = a + b; 138 | [fast_two_sum_tail(a, b, x), x] 139 | } 140 | 141 | #[inline] 142 | pub fn fast_two_diff_tail(a: f64, b: f64, x: f64) -> f64 { 143 | let bvirt: f64 = a - x; 144 | return bvirt - b; 145 | } 146 | 147 | #[inline] 148 | pub fn fast_two_diff(a: f64, b: f64) -> [f64; 2] { 149 | let x: f64 = a - b; 150 | [fast_two_diff_tail(a, b, x), x] 151 | } 152 | 153 | #[inline] 154 | pub fn two_sum_tail(a: f64, b: f64, x: f64) -> f64 { 155 | let bvirt: f64 = x - a; 156 | let avirt: f64 = x - bvirt; 157 | let bround: f64 = b - bvirt; 158 | let around: f64 = a - avirt; 159 | around + bround 160 | } 161 | 162 | #[inline] 163 | pub fn two_sum(a: f64, b: f64) -> [f64; 2] { 164 | let x: f64 = a + b; 165 | [two_sum_tail(a, b, x), x] 166 | } 167 | 168 | #[inline] 169 | pub fn two_diff_tail(a: f64, b: f64, x: f64) -> f64 { 170 | let bvirt: f64 = a - x; 171 | let avirt: f64 = x + bvirt; 172 | let bround: f64 = bvirt - b; 173 | let around: f64 = a - avirt; 174 | around + bround 175 | } 176 | 177 | #[inline] 178 | pub fn two_diff(a: f64, b: f64) -> [f64; 2] { 179 | let x: f64 = a - b; 180 | [two_diff_tail(a, b, x), x] 181 | } 182 | 183 | #[inline] 184 | pub fn split(a: f64) -> [f64; 2] { 185 | let c: f64 = PARAMS.splitter * a; 186 | let abig: f64 = c - a; 187 | let ahi = c - abig; 188 | let alo = a - ahi; 189 | [alo, ahi] 190 | } 191 | 192 | #[inline] 193 | pub fn two_product_tail(a: f64, b: f64, x: f64) -> f64 { 194 | let [alo, ahi] = split(a); 195 | let [blo, bhi] = split(b); 196 | let err1: f64 = x - ahi * bhi; 197 | let err2: f64 = err1 - alo * bhi; 198 | let err3: f64 = err2 - ahi * blo; 199 | alo * blo - err3 200 | } 201 | 202 | #[inline] 203 | pub fn two_product(a: f64, b: f64) -> [f64; 2] { 204 | let x = a * b; 205 | [two_product_tail(a, b, x), x] 206 | } 207 | 208 | /// Same as [`two_product`] where one of the inputs has 209 | /// already been split. 210 | /// 211 | /// Avoids redundant splitting. 212 | #[inline] 213 | pub fn two_product_presplit(a: f64, b: f64, bhi: f64, blo: f64) -> [f64; 2] { 214 | let x = a * b; 215 | let [alo, ahi] = split(a); 216 | let err1: f64 = x - ahi * bhi; 217 | let err2: f64 = err1 - alo * bhi; 218 | let err3: f64 = err2 - ahi * blo; 219 | [alo * blo - err3, x] 220 | } 221 | 222 | /// Same as [`two_product`] where both of the inputs have 223 | /// already been split. 224 | /// 225 | /// Avoids redundant splitting. 226 | #[inline] 227 | pub fn two_product_2presplit(a: f64, ahi: f64, alo: f64, b: f64, bhi: f64, blo: f64) -> [f64; 2] { 228 | let x = a * b; 229 | let err1: f64 = x - ahi * bhi; 230 | let err2: f64 = err1 - alo * bhi; 231 | let err3: f64 = err2 - ahi * blo; 232 | [alo * blo - err3, x] 233 | } 234 | 235 | #[inline] 236 | pub fn square_tail(a: f64, x: f64) -> f64 { 237 | let [alo, ahi] = split(a); 238 | let err1: f64 = x - ahi * ahi; 239 | let err3: f64 = err1 - (ahi + ahi) * alo; 240 | alo * alo - err3 241 | } 242 | 243 | /// Squaring can be done more quickly than [`two_product`]. 244 | #[inline] 245 | pub fn square(a: f64) -> [f64; 2] { 246 | let x = a * a; 247 | [square_tail(a, x), x] 248 | } 249 | 250 | // Macros for summing expansions of various fixed lengths. These are all 251 | // unrolled versions of expansion_sum(). 252 | 253 | #[inline] 254 | pub fn two_one_sum(a1: f64, a0: f64, b: f64) -> [f64; 3] { 255 | let [x0, _i] = two_sum(a0, b); 256 | let [x1, x2] = two_sum(a1, _i); 257 | [x0, x1, x2] 258 | } 259 | 260 | #[inline] 261 | pub fn two_one_diff(a1: f64, a0: f64, b: f64) -> [f64; 3] { 262 | let [x0, _i] = two_diff(a0, b); 263 | let [x1, x2] = two_sum(a1, _i); 264 | [x2, x1, x0] 265 | } 266 | 267 | #[inline] 268 | pub fn two_two_sum(a1: f64, a0: f64, b1: f64, b0: f64) -> [f64; 4] { 269 | let [x0, _0, _j] = two_one_sum(a1, a0, b0); 270 | let [x1, x2, x3] = two_one_sum(_j, _0, b1); 271 | [x0, x1, x2, x3] 272 | } 273 | 274 | #[inline] 275 | pub fn two_two_diff(a1: f64, a0: f64, b1: f64, b0: f64) -> [f64; 4] { 276 | let [_j, _0, x0] = two_one_diff(a1, a0, b0); 277 | let [x3, x2, x1] = two_one_diff(_j, _0, b1); 278 | [x0, x1, x2, x3] 279 | } 280 | 281 | #[inline] 282 | pub fn four_one_sum(a3: f64, a2: f64, a1: f64, a0: f64, b: f64) -> [f64; 5] { 283 | let [x0, x1, _j] = two_one_sum(a1, a0, b); 284 | let [x2, x3, x4] = two_one_sum(a3, a2, _j); 285 | [x0, x1, x2, x3, x4] 286 | } 287 | 288 | #[inline] 289 | pub fn four_two_sum(a3: f64, a2: f64, a1: f64, a0: f64, b1: f64, b0: f64) -> [f64; 6] { 290 | let [x0, _0, _1, _2, _k] = four_one_sum(a3, a2, a1, a0, b0); 291 | let [x1, x2, x3, x4, x5] = four_one_sum(_k, _2, _1, _0, b1); 292 | [x0, x1, x2, x3, x4, x5] 293 | } 294 | 295 | #[inline] 296 | pub fn four_four_sum( 297 | a3: f64, 298 | a2: f64, 299 | a1: f64, 300 | a0: f64, 301 | b4: f64, 302 | b3: f64, 303 | b1: f64, 304 | b0: f64, 305 | ) -> [f64; 8] { 306 | let [x0, x1, _0, _1, _2, _l] = four_two_sum(a3, a2, a1, a0, b1, b0); 307 | let [x2, x3, x4, x5, x6, x7] = four_two_sum(_l, _2, _1, _0, b4, b3); 308 | [x7, x6, x5, x4, x3, x2, x1, x0] 309 | } 310 | 311 | #[inline] 312 | pub fn eight_one_sum( 313 | a7: f64, 314 | a6: f64, 315 | a5: f64, 316 | a4: f64, 317 | a3: f64, 318 | a2: f64, 319 | a1: f64, 320 | a0: f64, 321 | b: f64, 322 | ) -> [f64; 9] { 323 | let [x0, x1, x2, x3, _j] = four_one_sum(a3, a2, a1, a0, b); 324 | let [x4, x5, x6, x7, x8] = four_one_sum(a7, a6, a5, a4, _j); 325 | [x0, x1, x2, x3, x4, x5, x6, x7, x8] 326 | } 327 | 328 | #[inline] 329 | pub fn eight_two_sum( 330 | a7: f64, 331 | a6: f64, 332 | a5: f64, 333 | a4: f64, 334 | a3: f64, 335 | a2: f64, 336 | a1: f64, 337 | a0: f64, 338 | b1: f64, 339 | b0: f64, 340 | ) -> [f64; 10] { 341 | let [x0, _0, _1, _2, _3, _4, _5, _6, _k] = eight_one_sum(a7, a6, a5, a4, a3, a2, a1, a0, b0); 342 | let [x1, x2, x3, x4, x5, x6, x7, x8, x9] = eight_one_sum(_k, _6, _5, _4, _3, _2, _1, _0, b1); 343 | [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] 344 | } 345 | 346 | #[inline] 347 | pub fn eight_four_sum( 348 | a7: f64, 349 | a6: f64, 350 | a5: f64, 351 | a4: f64, 352 | a3: f64, 353 | a2: f64, 354 | a1: f64, 355 | a0: f64, 356 | b4: f64, 357 | b3: f64, 358 | b1: f64, 359 | b0: f64, 360 | ) -> [f64; 12] { 361 | let [x0, x1, _0, _1, _2, _3, _4, _5, _6, _l] = 362 | eight_two_sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0); 363 | let [x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] = 364 | eight_two_sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3); 365 | [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] 366 | } 367 | 368 | // Macros for multiplying expansions of various fixed lengths. 369 | 370 | #[inline] 371 | pub fn two_one_product(a1: f64, a0: f64, b: f64) -> [f64; 4] { 372 | let [blo, bhi] = split(b); 373 | let [x0, _i] = two_product_presplit(a0, b, bhi, blo); 374 | let [_0, _j] = two_product_presplit(a1, b, bhi, blo); 375 | let [x1, _k] = two_sum(_i, _0); 376 | let [x2, x3] = fast_two_sum(_j, _k); 377 | [x0, x1, x2, x3] 378 | } 379 | 380 | #[inline] 381 | pub fn four_one_product(a3: f64, a2: f64, a1: f64, a0: f64, b: f64) -> [f64; 8] { 382 | let [blo, bhi] = split(b); 383 | let [x0, _i] = two_product_presplit(a0, b, bhi, blo); 384 | let [_0, _j] = two_product_presplit(a1, b, bhi, blo); 385 | let [x1, _k] = two_sum(_i, _0); 386 | let [x2, _i] = fast_two_sum(_j, _k); 387 | let [_0, _j] = two_product_presplit(a2, b, bhi, blo); 388 | let [x3, _k] = two_sum(_i, _0); 389 | let [x4, _i] = fast_two_sum(_j, _k); 390 | let [_0, _j] = two_product_presplit(a3, b, bhi, blo); 391 | let [x5, _k] = two_sum(_i, _0); 392 | let [x6, x7] = fast_two_sum(_j, _k); 393 | [x0, x1, x2, x3, x4, x5, x6, x7] 394 | } 395 | 396 | #[inline] 397 | pub fn two_two_product(a1: f64, a0: f64, b1: f64, b0: f64) -> [f64; 8] { 398 | let [a0lo, a0hi] = split(a0); 399 | let [blo, bhi] = split(b0); 400 | let [x0, _i] = two_product_2presplit(a0, a0hi, a0lo, b0, bhi, blo); 401 | let [a1lo, a1hi] = split(a1); 402 | let [_0, _j] = two_product_2presplit(a1, a1hi, a1lo, b0, bhi, blo); 403 | let [_1, _k] = two_sum(_i, _0); 404 | let [_2, _l] = fast_two_sum(_j, _k); 405 | let [blo, bhi] = split(b1); 406 | let [_0, _i] = two_product_2presplit(a0, a0hi, a0lo, b1, bhi, blo); 407 | let [x1, _k] = two_sum(_1, _0); 408 | let [_1, _j] = two_sum(_2, _k); 409 | let [_2, _m] = two_sum(_l, _j); 410 | let [_0, _j] = two_product_2presplit(a1, a1hi, a1lo, b1, bhi, blo); 411 | let [_0, _n] = two_sum(_i, _0); 412 | let [x2, _i] = two_sum(_1, _0); 413 | let [_1, _k] = two_sum(_2, _i); 414 | let [_2, _l] = two_sum(_m, _k); 415 | let [_0, _k] = two_sum(_j, _n); 416 | let [x3, _j] = two_sum(_1, _0); 417 | let [_1, _i] = two_sum(_2, _j); 418 | let [_2, _m] = two_sum(_l, _i); 419 | let [x4, _i] = two_sum(_1, _k); 420 | let [x5, _k] = two_sum(_2, _i); 421 | let [x6, x7] = two_sum(_m, _k); 422 | [x0, x1, x2, x3, x4, x5, x6, x7] 423 | } 424 | 425 | // An expansion of length two can be squared more quickly than finding the 426 | // product of two different expansions of length two, and the result is 427 | // guaranteed to have no more than six (rather than eight) components. 428 | 429 | #[inline] 430 | pub fn two_square(a1: f64, a0: f64) -> [f64; 6] { 431 | let [x0, _j] = square(a0); 432 | let _0: f64 = a0 + a0; 433 | let [_1, _k] = two_product(a1, _0); 434 | let [x1, _2, _l] = two_one_sum(_k, _1, _j); 435 | let [_1, _j] = square(a1); 436 | let [x2, x3, x4, x5] = two_two_sum(_j, _1, _l, _2); 437 | [x0, x1, x2, x3, x4, x5] 438 | } 439 | 440 | /// Adds a scalar to an expansion. 441 | /// 442 | /// Sets `h = e + b`. See [the paper](http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) for details. 443 | /// 444 | /// Maintains the nonoverlapping property. If round-to-even is used (as 445 | /// with IEEE 754), maintains the strongly nonoverlapping and nonadjacent 446 | /// properties as well. (That is, if `e` has one of these properties, so 447 | /// will `h`.) 448 | #[inline] 449 | pub fn grow_expansion(e: &[f64], b: f64, h: &mut [f64]) -> usize { 450 | let mut q = b; 451 | let mut eindex = 0; 452 | while eindex < e.len() { 453 | let [hnew, q_new] = two_sum(q, e[eindex]); 454 | q = q_new; 455 | h[eindex] = hnew; 456 | eindex += 1; 457 | } 458 | h[eindex] = q; 459 | eindex + 1 460 | } 461 | 462 | /// Adds a scalar to an expansion, eliminating zero components from the output 463 | /// expansion. 464 | /// 465 | /// Sets `h = e + b`. See [the paper](http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) for details. 466 | /// 467 | /// Maintains the nonoverlapping property. If round-to-even is used (as 468 | /// with IEEE 754), maintains the strongly nonoverlapping and nonadjacent 469 | /// properties as well. (That is, if `e` has one of these properties, so 470 | /// will `h`.) 471 | #[inline] 472 | pub fn grow_expansion_zeroelim(e: &[f64], b: f64, h: &mut [f64]) -> usize { 473 | let mut hindex = 0; 474 | let mut q = b; 475 | let mut eindex = 0; 476 | while eindex < e.len() { 477 | let [hh, q_new] = two_sum(q, e[eindex]); 478 | q = q_new; 479 | if hh != 0.0f64 { 480 | let fresh0 = hindex; 481 | hindex = hindex + 1; 482 | h[fresh0] = hh; 483 | } 484 | eindex += 1 485 | } 486 | if q != 0.0f64 || hindex == 0 { 487 | let fresh1 = hindex; 488 | hindex = hindex + 1; 489 | h[fresh1] = q; 490 | } 491 | hindex 492 | } 493 | 494 | /// Sums two expansions. 495 | /// 496 | /// Sets `h = e + f`. See [the paper](http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) for details. 497 | /// 498 | /// Maintains the nonoverlapping property. If round-to-even is used (as 499 | /// with IEEE 754), maintains the nonadjacent property as well. (That is, 500 | /// if `e` has one of these properties, so will `h`.) Does NOT maintain the 501 | /// strongly nonoverlapping property. 502 | #[inline] 503 | pub fn expansion_sum(e: &[f64], f: &[f64], h: &mut [f64]) -> usize { 504 | let mut q = f[0]; 505 | let mut hindex = 0; 506 | while hindex < e.len() { 507 | let [hh, qnew] = two_sum(q, e[hindex]); 508 | h[hindex] = hh; 509 | q = qnew; 510 | hindex += 1 511 | } 512 | h[hindex] = q; 513 | let mut hlast = hindex; 514 | let mut findex = 1; 515 | while findex < f.len() { 516 | q = f[findex]; 517 | hindex = findex; 518 | while hindex <= hlast { 519 | let [hh, qnew] = two_sum(q, h[hindex]); 520 | h[hindex] = hh; 521 | q = qnew; 522 | hindex += 1 523 | } 524 | hlast += 1; 525 | h[hlast] = q; 526 | findex += 1 527 | } 528 | hlast + 1 529 | } 530 | 531 | /// Sums two expansions, eliminating zero components from the output expansion. 532 | /// 533 | /// Sets `h = e + f`. See [the 534 | /// paper](http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) for details. 535 | /// 536 | /// Maintains the nonoverlapping property. If round-to-even is used (as 537 | /// with IEEE 754), maintains the nonadjacent property as well. (That is, 538 | /// if `e` has one of these properties, so will `h`.) Does NOT maintain the 539 | /// strongly nonoverlapping property. 540 | #[inline] 541 | pub fn expansion_sum_zeroelim1(e: &[f64], f: &[f64], h: &mut [f64]) -> usize { 542 | let mut q = f[0]; 543 | let mut hindex = 0; 544 | while hindex < e.len() { 545 | let [hh, qnew] = two_sum(q, e[hindex]); 546 | h[hindex] = hh; 547 | q = qnew; 548 | hindex += 1 549 | } 550 | h[hindex] = q; 551 | let mut hlast = hindex; 552 | let mut findex = 1; 553 | while findex < f.len() { 554 | q = f[findex]; 555 | hindex = findex; 556 | while hindex <= hlast { 557 | let [hh, qnew] = two_sum(q, h[hindex]); 558 | h[hindex] = hh; 559 | q = qnew; 560 | hindex += 1 561 | } 562 | hlast += 1; 563 | h[hlast] = q; 564 | findex += 1 565 | } 566 | let mut hindex: isize = -1; 567 | let mut index = 0; 568 | while index <= hlast { 569 | let hnow = h[index]; 570 | if hnow != 0.0 { 571 | hindex += 1; 572 | h[hindex as usize] = hnow 573 | } 574 | index += 1 575 | } 576 | if hindex == -1 { 577 | 1 578 | } else { 579 | hindex as usize + 1 580 | } 581 | } 582 | /// Sums two expansions, eliminating zero components from the output expansion. 583 | /// 584 | /// Sets `h = e + f`. See [the 585 | /// paper](http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) for details. 586 | /// 587 | /// Maintains the nonoverlapping property. If round-to-even is used (as 588 | /// with IEEE 754), maintains the nonadjacent property as well. (That is, 589 | /// if `e` has one of these properties, so will `h`.) Does NOT maintain the 590 | /// strongly nonoverlapping property. 591 | #[inline] 592 | pub fn expansion_sum_zeroelim2(e: &[f64], f: &[f64], h: &mut [f64]) -> usize { 593 | let mut hindex = 0; 594 | let mut q = f[0]; 595 | let mut eindex = 0; 596 | while eindex < e.len() { 597 | let [hh, qnew] = two_sum(q, e[eindex]); 598 | q = qnew; 599 | if hh != 0.0 { 600 | h[hindex] = hh; 601 | hindex += 1; 602 | } 603 | eindex += 1 604 | } 605 | h[hindex] = q; 606 | let mut hlast = hindex; 607 | let mut findex = 1; 608 | while findex < f.len() { 609 | hindex = 0; 610 | q = f[findex]; 611 | eindex = 0; 612 | while eindex <= hlast { 613 | let [hh, qnew] = two_sum(q, h[eindex]); 614 | q = qnew; 615 | if hh != 0.0 { 616 | h[hindex] = hh; 617 | hindex += 1; 618 | } 619 | eindex += 1 620 | } 621 | h[hindex] = q; 622 | hlast = hindex; 623 | findex += 1 624 | } 625 | hlast + 1 626 | } 627 | 628 | /* ****************************************************************************/ 629 | /* */ 630 | /* fast_expansion_sum() Sum two expansions. */ 631 | /* */ 632 | /* Sets h = e + f. See the long version of my paper for details. */ 633 | /* */ 634 | /* If round-to-even is used (as with IEEE 754), maintains the strongly */ 635 | /* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ 636 | /* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ 637 | /* properties. */ 638 | /* */ 639 | /* ****************************************************************************/ 640 | /* 641 | pub unsafe fn fast_expansion_sum(mut elen: i32, 642 | mut e: *const f64, 643 | mut flen: i32, 644 | mut f: *const f64, 645 | mut h: *mut f64) 646 | -> i32 { 647 | let mut Q: f64 = 0.; 648 | let mut Qnew: f64 = 0.; 649 | let mut bvirt: f64 = 0.; 650 | let mut avirt: f64 = 0.; 651 | let mut bround: f64 = 0.; 652 | let mut around: f64 = 0.; 653 | let mut eindex: i32 = 0; 654 | let mut findex: i32 = 0; 655 | let mut hindex: i32 = 0; 656 | let mut enow: f64 = 0.; 657 | let mut fnow: f64 = 0.; 658 | enow = e[0]; 659 | fnow = f[0]; 660 | findex = 0 as i32; 661 | eindex = findex; 662 | if (fnow > enow) as i32 == (fnow > -enow) as i32 { 663 | Q = enow; 664 | eindex += 1; 665 | enow = *e.offset(eindex as isize) 666 | } else { Q = fnow; findex += 1; fnow = *f.offset(findex as isize) } 667 | hindex = 0 as i32; 668 | if eindex < elen && findex < flen { 669 | if (fnow > enow) as i32 == (fnow > -enow) as i32 { 670 | let [y, x] = Fast_Two_Sum(enow, Q); 671 | Qnew = x; 672 | h[0] = y; 673 | eindex += 1; 674 | enow = *e.offset(eindex as isize) 675 | } else { 676 | let [y, x] = Fast_Two_Sum(fnow, Q); 677 | Qnew = x; 678 | h[0] = y; 679 | findex += 1; 680 | fnow = *f.offset(findex as isize) 681 | } 682 | Q = Qnew; 683 | hindex = 1 as i32; 684 | while eindex < elen && findex < flen { 685 | if (fnow > enow) as i32 == (fnow > -enow) as i32 { 686 | Two_Sum(Q, enow, &mut Qnew, &mut *h.offset(hindex as isize)); 687 | eindex += 1; 688 | enow = *e.offset(eindex as isize) 689 | } else { 690 | Two_Sum(Q, fnow, &mut Qnew, &mut *h.offset(hindex as isize)); 691 | findex += 1; 692 | fnow = *f.offset(findex as isize) 693 | } 694 | Q = Qnew; 695 | hindex += 1 696 | } 697 | } 698 | while eindex < elen { 699 | Two_Sum(Q, enow, &mut Qnew, &mut *h.offset(hindex as isize)); 700 | eindex += 1; 701 | enow = *e.offset(eindex as isize); 702 | Q = Qnew; 703 | hindex += 1 704 | } 705 | while findex < flen { 706 | Two_Sum(Q, fnow, &mut Qnew, &mut *h.offset(hindex as isize)); 707 | findex += 1; 708 | fnow = *f.offset(findex as isize); 709 | Q = Qnew; 710 | hindex += 1 711 | } 712 | *h.offset(hindex as isize) = Q; 713 | return hindex + 1 as i32; 714 | } 715 | */ 716 | 717 | /// Sums two expansions, eliminating zero components from the output expansion. 718 | /// 719 | /// Sets `h = e + f`. See [the 720 | /// paper](http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) for details. 721 | /// 722 | /// If round-to-even is used (as with IEEE 754), maintains the strongly 723 | /// nonoverlapping property. (That is, if `e` is strongly nonoverlapping, `h` 724 | /// will be also.) Does NOT maintain the nonoverlapping or nonadjacent 725 | /// properties. 726 | #[inline] 727 | pub fn fast_expansion_sum_zeroelim(e: &[f64], f: &[f64], h: &mut [f64]) -> usize { 728 | let mut q; 729 | let mut findex = 0; 730 | let mut eindex = findex; 731 | 732 | let enow = e[0]; 733 | let fnow = f[0]; 734 | if (fnow > enow) == (fnow > -enow) { 735 | q = enow; 736 | eindex += 1; 737 | } else { 738 | q = fnow; 739 | findex += 1; 740 | } 741 | 742 | let mut hindex = 0; 743 | if eindex < e.len() && findex < f.len() { 744 | let enow = e[eindex]; 745 | let fnow = f[findex]; 746 | let [hh, q_new] = if (fnow > enow) == (fnow > -enow) { 747 | eindex += 1; 748 | fast_two_sum(enow, q) 749 | } else { 750 | findex += 1; 751 | fast_two_sum(fnow, q) 752 | }; 753 | q = q_new; 754 | if hh != 0.0f64 { 755 | h[hindex] = hh; 756 | hindex += 1; 757 | } 758 | while eindex < e.len() && findex < f.len() { 759 | let enow = e[eindex]; 760 | let fnow = f[findex]; 761 | let [hh, q_new] = if (fnow > enow) == (fnow > -enow) { 762 | eindex += 1; 763 | two_sum(q, enow) 764 | } else { 765 | findex += 1; 766 | two_sum(q, fnow) 767 | }; 768 | q = q_new; 769 | if hh != 0.0f64 { 770 | h[hindex] = hh; 771 | hindex += 1; 772 | } 773 | } 774 | } 775 | while eindex < e.len() { 776 | let [hh, q_new] = two_sum(q, e[eindex]); 777 | eindex += 1; 778 | q = q_new; 779 | if hh != 0.0f64 { 780 | h[hindex] = hh; 781 | hindex += 1; 782 | } 783 | } 784 | while findex < f.len() { 785 | let [hh, q_new] = two_sum(q, f[findex]); 786 | findex += 1; 787 | q = q_new; 788 | if hh != 0.0f64 { 789 | h[hindex] = hh; 790 | hindex += 1; 791 | } 792 | } 793 | if q != 0.0f64 || hindex == 0 { 794 | h[hindex] = q; 795 | hindex += 1; 796 | } 797 | hindex 798 | } 799 | /* ****************************************************************************/ 800 | /* */ 801 | /* linear_expansion_sum() Sum two expansions. */ 802 | /* */ 803 | /* Sets h = e + f. See either version of my paper for details. */ 804 | /* */ 805 | /* Maintains the nonoverlapping property. (That is, if e is */ 806 | /* nonoverlapping, h will be also.) */ 807 | /* */ 808 | /* ****************************************************************************/ 809 | /* 810 | pub unsafe fn linear_expansion_sum(mut elen: i32, 811 | mut e: *const f64, 812 | mut flen: i32, 813 | mut f: *const f64, 814 | mut h: *mut f64) 815 | -> i32 { 816 | let mut Q: f64 = 0.; 817 | let mut q: f64 = 0.; 818 | let mut Qnew: f64 = 0.; 819 | let mut R: f64 = 0.; 820 | let mut bvirt: f64 = 0.; 821 | let mut avirt: f64 = 0.; 822 | let mut bround: f64 = 0.; 823 | let mut around: f64 = 0.; 824 | let mut eindex: i32 = 0; 825 | let mut findex: i32 = 0; 826 | let mut hindex: i32 = 0; 827 | let mut enow: f64 = 0.; 828 | let mut fnow: f64 = 0.; 829 | let mut g0: f64 = 0.; 830 | enow = e[0]; 831 | fnow = f[0]; 832 | findex = 0 as i32; 833 | eindex = findex; 834 | if (fnow > enow) as i32 == (fnow > -enow) as i32 { 835 | g0 = enow; 836 | eindex += 1; 837 | enow = *e.offset(eindex as isize) 838 | } else { g0 = fnow; findex += 1; fnow = *f.offset(findex as isize) } 839 | if eindex < elen && 840 | (findex >= flen || 841 | (fnow > enow) as i32 == (fnow > -enow) as i32) 842 | { 843 | let [y, x] = Fast_Two_Sum(enow, g0); 844 | Qnew = x; 845 | q = y; 846 | eindex += 1; 847 | enow = *e.offset(eindex as isize) 848 | } else { 849 | let [y, x] = Fast_Two_Sum(fnow, g0); 850 | Qnew = x; 851 | q = y; 852 | findex += 1; 853 | fnow = *f.offset(findex as isize) 854 | } 855 | Q = Qnew; 856 | hindex = 0 as i32; 857 | while hindex < elen + flen - 2 as i32 { 858 | if eindex < elen && 859 | (findex >= flen || 860 | (fnow > enow) as i32 == 861 | (fnow > -enow) as i32) { 862 | let [y, x] = Fast_Two_Sum(enow, q); 863 | R = x; 864 | *h.offset(hindex as isize) = y; 865 | eindex += 1; 866 | enow = *e.offset(eindex as isize) 867 | } else { 868 | let [y, x] = Fast_Two_Sum(fnow, q); 869 | R = x; 870 | *h.offset(hindex as isize) = y; 871 | findex += 1; 872 | fnow = *f.offset(findex as isize) 873 | } 874 | Two_Sum(Q, R, &mut Qnew, &mut q); 875 | Q = Qnew; 876 | hindex += 1 877 | } 878 | *h.offset(hindex as isize) = q; 879 | *h.offset((hindex + 1 as i32) as isize) = Q; 880 | return hindex + 2 as i32; 881 | } 882 | */ 883 | /* ****************************************************************************/ 884 | /* */ 885 | /* linear_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ 886 | /* components from the output expansion. */ 887 | /* */ 888 | /* Sets h = e + f. See either version of my paper for details. */ 889 | /* */ 890 | /* Maintains the nonoverlapping property. (That is, if e is */ 891 | /* nonoverlapping, h will be also.) */ 892 | /* */ 893 | /* ****************************************************************************/ 894 | 895 | /* 896 | pub unsafe fn linear_expansion_sum_zeroelim(mut elen: i32, 897 | mut e: 898 | *const f64, 899 | mut flen: i32, 900 | mut f: 901 | *const f64, 902 | mut h: 903 | *mut f64) 904 | -> i32 { 905 | let mut Q: f64 = 0.; 906 | let mut q: f64 = 0.; 907 | let mut hh: f64 = 0.; 908 | let mut Qnew: f64 = 0.; 909 | let mut R: f64 = 0.; 910 | let mut bvirt: f64 = 0.; 911 | let mut avirt: f64 = 0.; 912 | let mut bround: f64 = 0.; 913 | let mut around: f64 = 0.; 914 | let mut eindex: i32 = 0; 915 | let mut findex: i32 = 0; 916 | let mut hindex: i32 = 0; 917 | let mut count: i32 = 0; 918 | let mut enow: f64 = 0.; 919 | let mut fnow: f64 = 0.; 920 | let mut g0: f64 = 0.; 921 | enow = e[0]; 922 | fnow = f[0]; 923 | findex = 0 as i32; 924 | eindex = findex; 925 | hindex = 0 as i32; 926 | if (fnow > enow) as i32 == (fnow > -enow) as i32 { 927 | g0 = enow; 928 | eindex += 1; 929 | enow = *e.offset(eindex as isize) 930 | } else { g0 = fnow; findex += 1; fnow = *f.offset(findex as isize) } 931 | if eindex < elen && 932 | (findex >= flen || 933 | (fnow > enow) as i32 == (fnow > -enow) as i32) 934 | { 935 | let [y, x] = Fast_Two_Sum(enow, g0); 936 | Qnew = x; 937 | q = y; 938 | eindex += 1; 939 | enow = *e.offset(eindex as isize) 940 | } else { 941 | let [y, x] = Fast_Two_Sum(fnow, g0); 942 | Qnew = x; 943 | q = y; 944 | findex += 1; 945 | fnow = *f.offset(findex as isize) 946 | } 947 | Q = Qnew; 948 | count = 2 as i32; 949 | while count < elen + flen { 950 | if eindex < elen && 951 | (findex >= flen || 952 | (fnow > enow) as i32 == 953 | (fnow > -enow) as i32) { 954 | let [y, x] = Fast_Two_Sum(enow, q); 955 | R = x; 956 | hh = y; 957 | eindex += 1; 958 | enow = *e.offset(eindex as isize) 959 | } else { 960 | let [y, x] = Fast_Two_Sum(fnow, q); 961 | R = x; 962 | hh = y; 963 | findex += 1; 964 | fnow = *f.offset(findex as isize) 965 | } 966 | Two_Sum(Q, R, &mut Qnew, &mut q); 967 | Q = Qnew; 968 | if hh != 0 as i32 as f64 { 969 | let fresh9 = hindex; 970 | hindex = hindex + 1; 971 | *h.offset(fresh9 as isize) = hh 972 | } 973 | count += 1 974 | } 975 | if q != 0 as i32 as f64 { 976 | let fresh10 = hindex; 977 | hindex = hindex + 1; 978 | *h.offset(fresh10 as isize) = q 979 | } 980 | if Q != 0.0f64 || hindex == 0 as i32 { 981 | let fresh11 = hindex; 982 | hindex = hindex + 1; 983 | *h.offset(fresh11 as isize) = Q 984 | } 985 | return hindex; 986 | } 987 | */ 988 | /* ****************************************************************************/ 989 | /* */ 990 | /* scale_expansion() Multiply an expansion by a scalar. */ 991 | /* */ 992 | /* Sets h = be. See either version of my paper for details. */ 993 | /* */ 994 | /* Maintains the nonoverlapping property. If round-to-even is used (as */ 995 | /* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ 996 | /* properties as well. (That is, if e has one of these properties, so */ 997 | /* will h.) */ 998 | /* */ 999 | /* ****************************************************************************/ 1000 | /* 1001 | pub unsafe fn scale_expansion(mut elen: i32, 1002 | mut e: *const f64, 1003 | mut b: f64, 1004 | mut h: *mut f64) 1005 | -> i32 { 1006 | let mut Q: f64 = 0.; 1007 | let mut sum: f64 = 0.; 1008 | let mut product1: f64 = 0.; 1009 | let mut product0: f64 = 0.; 1010 | let mut eindex: i32 = 0; 1011 | let mut hindex: i32 = 0; 1012 | let mut enow: f64 = 0.; 1013 | let mut bvirt: f64 = 0.; 1014 | let mut avirt: f64 = 0.; 1015 | let mut bround: f64 = 0.; 1016 | let mut around: f64 = 0.; 1017 | let mut c: f64 = 0.; 1018 | let mut abig: f64 = 0.; 1019 | let mut ahi: f64 = 0.; 1020 | let mut alo: f64 = 0.; 1021 | let mut bhi: f64 = 0.; 1022 | let mut blo: f64 = 0.; 1023 | let mut err1: f64 = 0.; 1024 | let mut err2: f64 = 0.; 1025 | let mut err3: f64 = 0.; 1026 | Split(b, &mut bhi, &mut blo); 1027 | Two_Product_Presplit(e[0], b, bhi, blo, 1028 | &mut Q, &mut h[0]); 1029 | hindex = 1 as i32; 1030 | eindex = 1 as i32; 1031 | while eindex < elen { 1032 | enow = *e.offset(eindex as isize); 1033 | Two_Product_Presplit(enow, b, bhi, blo, &mut product1, &mut product0); 1034 | Two_Sum(Q, product0, &mut sum, &mut *h.offset(hindex as isize)); 1035 | hindex += 1; 1036 | Two_Sum(product1, sum, &mut Q, &mut *h.offset(hindex as isize)); 1037 | hindex += 1; 1038 | eindex += 1 1039 | } 1040 | *h.offset(hindex as isize) = Q; 1041 | return elen + elen; 1042 | } 1043 | */ 1044 | 1045 | /// Multiply an expansion by a scalar, eliminating zero components from the 1046 | /// output expansion. 1047 | /// 1048 | /// Sets `h = be`. See either [\[1\]] or [\[2\]] for details. 1049 | /// 1050 | /// Maintains the nonoverlapping property. If round-to-even is used (as 1051 | /// with IEEE 754), maintains the strongly nonoverlapping and nonadjacent 1052 | /// properties as well. (That is, if `e` has one of these properties, so 1053 | /// will `h`.) 1054 | /// 1055 | /// [\[1\]]: http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf 1056 | /// [\[2\]]: http://www.cs.berkeley.edu/~jrs/papers/robust-predicates.pdf 1057 | pub fn scale_expansion_zeroelim(e: &[f64], b: f64, h: &mut [f64]) -> usize { 1058 | let [blo, bhi] = split(b); 1059 | let [hh, mut q] = two_product_presplit(e[0], b, bhi, blo); 1060 | 1061 | let mut hindex = 0; 1062 | if hh != 0.0f64 { 1063 | h[hindex] = hh; 1064 | hindex += 1; 1065 | } 1066 | for &enow in e.iter().skip(1) { 1067 | let [product0, product1] = two_product_presplit(enow, b, bhi, blo); 1068 | let [hh, sum] = two_sum(q, product0); 1069 | if hh != 0.0f64 { 1070 | h[hindex] = hh; 1071 | hindex += 1; 1072 | } 1073 | let [hh, q_new] = fast_two_sum(product1, sum); 1074 | q = q_new; 1075 | if hh != 0.0f64 { 1076 | h[hindex] = hh; 1077 | hindex += 1; 1078 | } 1079 | } 1080 | if q != 0.0f64 || hindex == 0 { 1081 | h[hindex] = q; 1082 | hindex += 1; 1083 | } 1084 | hindex 1085 | } 1086 | 1087 | /* ****************************************************************************/ 1088 | /* */ 1089 | /* compress() Compress an expansion. */ 1090 | /* */ 1091 | /* See the long version of my paper for details. */ 1092 | /* */ 1093 | /* Maintains the nonoverlapping property. If round-to-even is used (as */ 1094 | /* with IEEE 754), then any nonoverlapping expansion is converted to a */ 1095 | /* nonadjacent expansion. */ 1096 | /* */ 1097 | /* ****************************************************************************/ 1098 | /* 1099 | pub unsafe fn compress(mut elen: i32, 1100 | mut e: *const f64, 1101 | mut h: *mut f64) -> i32 { 1102 | let mut Q: f64 = 0.; 1103 | let mut q: f64 = 0.; 1104 | let mut Qnew: f64 = 0.; 1105 | let mut eindex: i32 = 0; 1106 | let mut hindex: i32 = 0; 1107 | let mut bvirt: f64 = 0.; 1108 | let mut enow: f64 = 0.; 1109 | let mut hnow: f64 = 0.; 1110 | let mut top: i32 = 0; 1111 | let mut bottom: i32 = 0; 1112 | bottom = elen - 1 as i32; 1113 | Q = *e.offset(bottom as isize); 1114 | eindex = elen - 2 as i32; 1115 | while eindex >= 0 as i32 { 1116 | enow = *e.offset(eindex as isize); 1117 | let [y, x] = Fast_Two_Sum(Q, enow); 1118 | Qnew = x; 1119 | q = y; 1120 | if q != 0 as i32 as f64 { 1121 | let fresh16 = bottom; 1122 | bottom = bottom - 1; 1123 | *h.offset(fresh16 as isize) = Qnew; 1124 | Q = q 1125 | } else { Q = Qnew } 1126 | eindex -= 1 1127 | } 1128 | top = 0 as i32; 1129 | hindex = bottom + 1 as i32; 1130 | while hindex < elen { 1131 | hnow = *h.offset(hindex as isize); 1132 | let mut sum: [f64; 2] = [0.; 2]; 1133 | let [y, x] = Fast_Two_Sum(hnow, Q); 1134 | Qnew = x; 1135 | q = y; 1136 | if q != 0 as i32 as f64 { 1137 | let fresh17 = top; 1138 | top = top + 1; 1139 | *h.offset(fresh17 as isize) = q 1140 | } 1141 | Q = Qnew; 1142 | hindex += 1 1143 | } 1144 | *h.offset(top as isize) = Q; 1145 | return top + 1 as i32; 1146 | } 1147 | */ 1148 | 1149 | /* ****************************************************************************/ 1150 | /* */ 1151 | /* orient2d_fast() Approximate 2D orientation test. Nonrobust. */ 1152 | /* orient2d_exact() Exact 2D orientation test. Robust. */ 1153 | /* orient2d_slow() Another exact 2D orientation test. Robust. */ 1154 | /* orient2d() Adaptive exact 2D orientation test. Robust. */ 1155 | /* */ 1156 | /* Return a positive value if the points pa, pb, and pc occur */ 1157 | /* in counterclockwise order; a negative value if they occur */ 1158 | /* in clockwise order; and zero if they are collinear. The */ 1159 | /* result is also a rough approximation of twice the signed */ 1160 | /* area of the triangle defined by the three points. */ 1161 | /* */ 1162 | /* Only the first and last routine should be used; the middle two are for */ 1163 | /* timings. */ 1164 | /* */ 1165 | /* The last three use exact arithmetic to ensure a correct answer. The */ 1166 | /* result returned is the determinant of a matrix. In orient2d() only, */ 1167 | /* this determinant is computed adaptively, in the sense that exact */ 1168 | /* arithmetic is used only to the degree it is needed to ensure that the */ 1169 | /* returned value has the correct sign. Hence, orient2d() is usually quite */ 1170 | /* fast, but will run more slowly when the input points are collinear or */ 1171 | /* nearly so. */ 1172 | /* */ 1173 | /* ****************************************************************************/ 1174 | 1175 | /// Approximate 2D orientation test. Non-robust version of [`orient2d`]. 1176 | #[inline] 1177 | pub fn orient2d_fast(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2]) -> f64 { 1178 | let acx = pa[0] - pc[0]; 1179 | let bcx = pb[0] - pc[0]; 1180 | let acy = pa[1] - pc[1]; 1181 | let bcy = pb[1] - pc[1]; 1182 | acx * bcy - acy * bcx 1183 | } 1184 | 1185 | #[inline] 1186 | pub fn orient2d_exact(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2]) -> f64 { 1187 | let [axby0, axby1] = two_product(pa[0], pb[1]); 1188 | let [axcy0, axcy1] = two_product(pa[0], pc[1]); 1189 | let aterms = two_two_diff(axby1, axby0, axcy1, axcy0); 1190 | let [bxcy0, bxcy1] = two_product(pb[0], pc[1]); 1191 | let [bxay0, bxay1] = two_product(pb[0], pa[1]); 1192 | let bterms = two_two_diff(bxcy1, bxcy0, bxay1, bxay0); 1193 | let [cxay0, cxay1] = two_product(pc[0], pa[1]); 1194 | let [cxby0, cxby1] = two_product(pc[0], pb[1]); 1195 | let cterms = two_two_diff(cxay1, cxay0, cxby1, cxby0); 1196 | let mut v = [0.; 8]; 1197 | let vlength = fast_expansion_sum_zeroelim(&aterms, &bterms, &mut v); 1198 | let mut w = [0.; 12]; 1199 | let wlength = fast_expansion_sum_zeroelim(&v[..vlength], &cterms, &mut w); 1200 | w[wlength - 1] 1201 | } 1202 | 1203 | #[inline] 1204 | pub fn orient2d_slow(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2]) -> f64 { 1205 | let [acxtail, acx] = two_diff(pa[0], pc[0]); 1206 | let [acytail, acy] = two_diff(pa[1], pc[1]); 1207 | let [bcxtail, bcx] = two_diff(pb[0], pc[0]); 1208 | let [bcytail, bcy] = two_diff(pb[1], pc[1]); 1209 | let axby = two_two_product(acx, acxtail, bcy, bcytail); 1210 | let negate = -acy; 1211 | let negatetail = -acytail; 1212 | let bxay = two_two_product(bcx, bcxtail, negate, negatetail); 1213 | let mut deter = [0.; 16]; 1214 | let deterlen = fast_expansion_sum_zeroelim(&axby, &bxay, &mut deter); 1215 | deter[deterlen - 1] 1216 | } 1217 | 1218 | #[inline] 1219 | pub fn orient2dadapt(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2], detsum: f64) -> f64 { 1220 | let acx = pa[0] - pc[0]; 1221 | let bcx = pb[0] - pc[0]; 1222 | let acy = pa[1] - pc[1]; 1223 | let bcy = pb[1] - pc[1]; 1224 | let [detlefttail, detleft] = two_product(acx, bcy); 1225 | let [detrighttail, detright] = two_product(acy, bcx); 1226 | let b = two_two_diff(detleft, detlefttail, detright, detrighttail); 1227 | let mut det: f64 = b.iter().sum(); 1228 | let errbound = PARAMS.ccwerrbound_b * detsum; 1229 | if det >= errbound || -det >= errbound { 1230 | return det; 1231 | } 1232 | let acxtail = two_diff_tail(pa[0], pc[0], acx); 1233 | let bcxtail = two_diff_tail(pb[0], pc[0], bcx); 1234 | let acytail = two_diff_tail(pa[1], pc[1], acy); 1235 | let bcytail = two_diff_tail(pb[1], pc[1], bcy); 1236 | if acxtail == 0.0 && acytail == 0.0 && bcxtail == 0.0 && bcytail == 0.0 { 1237 | return det; 1238 | } 1239 | let errbound = PARAMS.ccwerrbound_c * detsum + PARAMS.resulterrbound * abs(det); 1240 | det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail); 1241 | if det >= errbound || -det >= errbound { 1242 | return det; 1243 | } 1244 | let [s0, s1] = two_product(acxtail, bcy); 1245 | let [t0, t1] = two_product(acytail, bcx); 1246 | let u = two_two_diff(s1, s0, t1, t0); 1247 | let mut c1: [f64; 8] = [0.; 8]; 1248 | let c1length = fast_expansion_sum_zeroelim(&b, &u, &mut c1); 1249 | let [s0, s1] = two_product(acx, bcytail); 1250 | let [t0, t1] = two_product(acy, bcxtail); 1251 | let u = two_two_diff(s1, s0, t1, t0); 1252 | let mut c2: [f64; 12] = [0.; 12]; 1253 | let c2length = fast_expansion_sum_zeroelim(&c1[..c1length], &u, &mut c2); 1254 | let [s0, s1] = two_product(acxtail, bcytail); 1255 | let [t0, t1] = two_product(acytail, bcxtail); 1256 | let u = two_two_diff(s1, s0, t1, t0); 1257 | let mut d: [f64; 16] = [0.; 16]; 1258 | let dlength = fast_expansion_sum_zeroelim(&c2[..c2length], &u, &mut d); 1259 | d[dlength - 1] 1260 | } 1261 | 1262 | /** 1263 | * Adaptive exact 2D orientation test. Robust. 1264 | * 1265 | * Return a positive value if the points `pa`, `pb`, and `pc` occur 1266 | * in counterclockwise order; a negative value if they occur 1267 | * in clockwise order; and zero if they are collinear. The 1268 | * result is also a rough approximation of twice the signed 1269 | * area of the triangle defined by the three points. 1270 | * 1271 | * The result returned is the determinant of a matrix. 1272 | * This determinant is computed adaptively, in the sense that exact 1273 | * arithmetic is used only to the degree it is needed to ensure that the 1274 | * returned value has the correct sign. Hence, `orient2d()` is usually quite 1275 | * fast, but will run more slowly when the input points are collinear or 1276 | * nearly so. 1277 | */ 1278 | #[inline] 1279 | pub fn orient2d(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2]) -> f64 { 1280 | let detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); 1281 | let detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); 1282 | let det = detleft - detright; 1283 | let detsum = if detleft > 0.0 { 1284 | if detright <= 0.0 { 1285 | return det; 1286 | } else { 1287 | detleft + detright 1288 | } 1289 | } else if detleft < 0.0 { 1290 | if detright >= 0.0 { 1291 | return det; 1292 | } else { 1293 | -detleft - detright 1294 | } 1295 | } else { 1296 | return det; 1297 | }; 1298 | let errbound = PARAMS.ccwerrbound_a * detsum; 1299 | if det >= errbound || -det >= errbound { 1300 | return det; 1301 | } 1302 | orient2dadapt(pa, pb, pc, detsum) 1303 | } 1304 | 1305 | /* ****************************************************************************/ 1306 | /* */ 1307 | /* orient3d_fast() Approximate 3D orientation test. Nonrobust. */ 1308 | /* orient3d_exact() Exact 3D orientation test. Robust. */ 1309 | /* orient3d_slow() Another exact 3D orientation test. Robust. */ 1310 | /* orient3d() Adaptive exact 3D orientation test. Robust. */ 1311 | /* */ 1312 | /* Return a positive value if the point pd lies below the */ 1313 | /* plane passing through pa, pb, and pc; "below" is defined so */ 1314 | /* that pa, pb, and pc appear in counterclockwise order when */ 1315 | /* viewed from above the plane. Returns a negative value if */ 1316 | /* pd lies above the plane. Returns zero if the points are */ 1317 | /* coplanar. The result is also a rough approximation of six */ 1318 | /* times the signed volume of the tetrahedron defined by the */ 1319 | /* four points. */ 1320 | /* */ 1321 | /* Only the first and last routine should be used; the middle two are for */ 1322 | /* timings. */ 1323 | /* */ 1324 | /* The last three use exact arithmetic to ensure a correct answer. The */ 1325 | /* result returned is the determinant of a matrix. In orient3d() only, */ 1326 | /* this determinant is computed adaptively, in the sense that exact */ 1327 | /* arithmetic is used only to the degree it is needed to ensure that the */ 1328 | /* returned value has the correct sign. Hence, orient3d() is usually quite */ 1329 | /* fast, but will run more slowly when the input points are coplanar or */ 1330 | /* nearly so. */ 1331 | /* */ 1332 | /* ****************************************************************************/ 1333 | 1334 | /// Approximate 3D orientation test. Non-robust version of [`orient3d`]. 1335 | #[inline] 1336 | pub fn orient3d_fast(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3]) -> f64 { 1337 | let adx = pa[0] - pd[0]; 1338 | let bdx = pb[0] - pd[0]; 1339 | let cdx = pc[0] - pd[0]; 1340 | let ady = pa[1] - pd[1]; 1341 | let bdy = pb[1] - pd[1]; 1342 | let cdy = pc[1] - pd[1]; 1343 | let adz = pa[2] - pd[2]; 1344 | let bdz = pb[2] - pd[2]; 1345 | let cdz = pc[2] - pd[2]; 1346 | adx * (bdy * cdz - bdz * cdy) + bdx * (cdy * adz - cdz * ady) + cdx * (ady * bdz - adz * bdy) 1347 | } 1348 | 1349 | #[inline] 1350 | pub fn orient3d_exact(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3]) -> f64 { 1351 | let [axby0, axby1] = two_product(pa[0], pb[1]); 1352 | let [bxay0, bxay1] = two_product(pb[0], pa[1]); 1353 | let ab = two_two_diff(axby1, axby0, bxay1, bxay0); 1354 | let [bxcy0, bxcy1] = two_product(pb[0], pc[1]); 1355 | let [cxby0, cxby1] = two_product(pc[0], pb[1]); 1356 | let bc = two_two_diff(bxcy1, bxcy0, cxby1, cxby0); 1357 | let [cxdy0, cxdy1] = two_product(pc[0], pd[1]); 1358 | let [dxcy0, dxcy1] = two_product(pd[0], pc[1]); 1359 | let cd = two_two_diff(cxdy1, cxdy0, dxcy1, dxcy0); 1360 | let [dxay0, dxay1] = two_product(pd[0], pa[1]); 1361 | let [axdy0, axdy1] = two_product(pa[0], pd[1]); 1362 | let da = two_two_diff(dxay1, dxay0, axdy1, axdy0); 1363 | let [axcy0, axcy1] = two_product(pa[0], pc[1]); 1364 | let [cxay0, cxay1] = two_product(pc[0], pa[1]); 1365 | let mut ac = two_two_diff(axcy1, axcy0, cxay1, cxay0); 1366 | let [bxdy0, bxdy1] = two_product(pb[0], pd[1]); 1367 | let [dxby0, dxby1] = two_product(pd[0], pb[1]); 1368 | let mut bd = two_two_diff(bxdy1, bxdy0, dxby1, dxby0); 1369 | 1370 | let mut temp8 = [0.; 8]; 1371 | let mut abc = [0.; 12]; 1372 | let mut bcd = [0.; 12]; 1373 | let mut cda = [0.; 12]; 1374 | let mut dab = [0.; 12]; 1375 | let mut adet = [0.; 24]; 1376 | let mut bdet = [0.; 24]; 1377 | let mut cdet = [0.; 24]; 1378 | let mut ddet = [0.; 24]; 1379 | let mut abdet = [0.; 48]; 1380 | let mut cddet = [0.; 48]; 1381 | let mut deter = [0.; 96]; 1382 | 1383 | let templen = fast_expansion_sum_zeroelim(&cd, &da, &mut temp8); 1384 | let cdalen = fast_expansion_sum_zeroelim(&temp8[..templen], &ac, &mut cda); 1385 | let templen = fast_expansion_sum_zeroelim(&da, &ab, &mut temp8); 1386 | let dablen = fast_expansion_sum_zeroelim(&temp8[..templen], &bd, &mut dab); 1387 | bd.iter_mut().for_each(|x| *x = -*x); 1388 | ac.iter_mut().for_each(|x| *x = -*x); 1389 | let templen = fast_expansion_sum_zeroelim(&ab, &bc, &mut temp8); 1390 | let abclen = fast_expansion_sum_zeroelim(&temp8[..templen], &ac, &mut abc); 1391 | let templen = fast_expansion_sum_zeroelim(&bc, &cd, &mut temp8); 1392 | let bcdlen = fast_expansion_sum_zeroelim(&temp8[..templen], &bd, &mut bcd); 1393 | let alen = scale_expansion_zeroelim(&bcd[..bcdlen], pa[2], &mut adet); 1394 | let blen = scale_expansion_zeroelim(&cda[..cdalen], -pb[2], &mut bdet); 1395 | let clen = scale_expansion_zeroelim(&dab[..dablen], pc[2], &mut cdet); 1396 | let dlen = scale_expansion_zeroelim(&abc[..abclen], -pd[2], &mut ddet); 1397 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 1398 | let cdlen = fast_expansion_sum_zeroelim(&cdet[..clen], &ddet[..dlen], &mut cddet); 1399 | let deterlen = fast_expansion_sum_zeroelim(&abdet[..ablen], &cddet[..cdlen], &mut deter); 1400 | deter[deterlen - 1] 1401 | } 1402 | 1403 | #[inline] 1404 | pub fn orient3d_slow(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3]) -> f64 { 1405 | let mut temp16: [f64; 16] = [0.; 16]; 1406 | let mut temp32: [f64; 32] = [0.; 32]; 1407 | let mut temp32t: [f64; 32] = [0.; 32]; 1408 | let mut adet: [f64; 64] = [0.; 64]; 1409 | let mut bdet: [f64; 64] = [0.; 64]; 1410 | let mut cdet: [f64; 64] = [0.; 64]; 1411 | let mut abdet: [f64; 128] = [0.; 128]; 1412 | let mut deter: [f64; 192] = [0.; 192]; 1413 | let [adxtail, adx] = two_diff(pa[0], pd[0]); 1414 | let [adytail, ady] = two_diff(pa[1], pd[1]); 1415 | let [adztail, adz] = two_diff(pa[2], pd[2]); 1416 | let [bdxtail, bdx] = two_diff(pb[0], pd[0]); 1417 | let [bdytail, bdy] = two_diff(pb[1], pd[1]); 1418 | let [bdztail, bdz] = two_diff(pb[2], pd[2]); 1419 | let [cdxtail, cdx] = two_diff(pc[0], pd[0]); 1420 | let [cdytail, cdy] = two_diff(pc[1], pd[1]); 1421 | let [cdztail, cdz] = two_diff(pc[2], pd[2]); 1422 | let axby = two_two_product(adx, adxtail, bdy, bdytail); 1423 | let negate = -ady; 1424 | let negatetail = -adytail; 1425 | let bxay = two_two_product(bdx, bdxtail, negate, negatetail); 1426 | let bxcy = two_two_product(bdx, bdxtail, cdy, cdytail); 1427 | let negate = -bdy; 1428 | let negatetail = -bdytail; 1429 | let cxby = two_two_product(cdx, cdxtail, negate, negatetail); 1430 | let cxay = two_two_product(cdx, cdxtail, ady, adytail); 1431 | let negate = -cdy; 1432 | let negatetail = -cdytail; 1433 | let axcy = two_two_product(adx, adxtail, negate, negatetail); 1434 | let temp16len = fast_expansion_sum_zeroelim(&bxcy, &cxby, &mut temp16); 1435 | let temp32len = scale_expansion_zeroelim(&temp16[..temp16len], adz, &mut temp32); 1436 | let temp32tlen = scale_expansion_zeroelim(&temp16[..temp16len], adztail, &mut temp32t); 1437 | let alen = fast_expansion_sum_zeroelim(&temp32[..temp32len], &temp32t[..temp32tlen], &mut adet); 1438 | let temp16len = fast_expansion_sum_zeroelim(&cxay, &axcy, &mut temp16); 1439 | let temp32len = scale_expansion_zeroelim(&temp16[..temp16len], bdz, &mut temp32); 1440 | let temp32tlen = scale_expansion_zeroelim(&temp16[..temp16len], bdztail, &mut temp32t); 1441 | let blen = fast_expansion_sum_zeroelim(&temp32[..temp32len], &temp32t[..temp32tlen], &mut bdet); 1442 | let temp16len = fast_expansion_sum_zeroelim(&axby, &bxay, &mut temp16); 1443 | let temp32len = scale_expansion_zeroelim(&temp16[..temp16len], cdz, &mut temp32); 1444 | let temp32tlen = scale_expansion_zeroelim(&temp16[..temp16len], cdztail, &mut temp32t); 1445 | let clen = fast_expansion_sum_zeroelim(&temp32[..temp32len], &temp32t[..temp32tlen], &mut cdet); 1446 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 1447 | let deterlen = fast_expansion_sum_zeroelim(&abdet[..ablen], &cdet[..clen], &mut deter); 1448 | deter[deterlen - 1] 1449 | } 1450 | 1451 | #[inline] 1452 | pub fn orient3dadapt( 1453 | pa: [f64; 3], 1454 | pb: [f64; 3], 1455 | pc: [f64; 3], 1456 | pd: [f64; 3], 1457 | permanent: f64, 1458 | ) -> f64 { 1459 | let adx = pa[0] - pd[0]; 1460 | let bdx = pb[0] - pd[0]; 1461 | let cdx = pc[0] - pd[0]; 1462 | let ady = pa[1] - pd[1]; 1463 | let bdy = pb[1] - pd[1]; 1464 | let cdy = pc[1] - pd[1]; 1465 | let adz = pa[2] - pd[2]; 1466 | let bdz = pb[2] - pd[2]; 1467 | let cdz = pc[2] - pd[2]; 1468 | 1469 | let [bdxcdy0, bdxcdy1] = two_product(bdx, cdy); 1470 | let [cdxbdy0, cdxbdy1] = two_product(cdx, bdy); 1471 | let bc = two_two_diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0); 1472 | let mut adet = [0.; 8]; 1473 | let alen = scale_expansion_zeroelim(&bc, adz, &mut adet); 1474 | 1475 | let [cdxady0, cdxady1] = two_product(cdx, ady); 1476 | let [adxcdy0, adxcdy1] = two_product(adx, cdy); 1477 | let ca = two_two_diff(cdxady1, cdxady0, adxcdy1, adxcdy0); 1478 | let mut bdet = [0.; 8]; 1479 | let blen = scale_expansion_zeroelim(&ca, bdz, &mut bdet); 1480 | 1481 | let [adxbdy0, adxbdy1] = two_product(adx, bdy); 1482 | let [bdxady0, bdxady1] = two_product(bdx, ady); 1483 | let ab = two_two_diff(adxbdy1, adxbdy0, bdxady1, bdxady0); 1484 | let mut cdet = [0.; 8]; 1485 | let clen = scale_expansion_zeroelim(&ab, cdz, &mut cdet); 1486 | 1487 | let mut abdet = [0.; 16]; 1488 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 1489 | let mut fin1 = [0.; 192]; 1490 | let mut finlength = fast_expansion_sum_zeroelim(&abdet[..ablen], &cdet[..clen], &mut fin1); 1491 | 1492 | let mut det: f64 = fin1[..finlength].iter().sum(); 1493 | let errbound = PARAMS.o3derrbound_b * permanent; 1494 | if det >= errbound || -det >= errbound { 1495 | return det; 1496 | } 1497 | 1498 | let adxtail = two_diff_tail(pa[0], pd[0], adx); 1499 | let bdxtail = two_diff_tail(pb[0], pd[0], bdx); 1500 | let cdxtail = two_diff_tail(pc[0], pd[0], cdx); 1501 | let adytail = two_diff_tail(pa[1], pd[1], ady); 1502 | let bdytail = two_diff_tail(pb[1], pd[1], bdy); 1503 | let cdytail = two_diff_tail(pc[1], pd[1], cdy); 1504 | let adztail = two_diff_tail(pa[2], pd[2], adz); 1505 | let bdztail = two_diff_tail(pb[2], pd[2], bdz); 1506 | let cdztail = two_diff_tail(pc[2], pd[2], cdz); 1507 | if adxtail == 0.0 1508 | && bdxtail == 0.0 1509 | && cdxtail == 0.0 1510 | && adytail == 0.0 1511 | && bdytail == 0.0 1512 | && cdytail == 0.0 1513 | && adztail == 0.0 1514 | && bdztail == 0.0 1515 | && cdztail == 0.0 1516 | { 1517 | return det; 1518 | } 1519 | let errbound = PARAMS.o3derrbound_c * permanent + PARAMS.resulterrbound * abs(det); 1520 | det += adz * (bdx * cdytail + cdy * bdxtail - (bdy * cdxtail + cdx * bdytail)) 1521 | + adztail * (bdx * cdy - bdy * cdx) 1522 | + (bdz * (cdx * adytail + ady * cdxtail - (cdy * adxtail + adx * cdytail)) 1523 | + bdztail * (cdx * ady - cdy * adx)) 1524 | + (cdz * (adx * bdytail + bdy * adxtail - (ady * bdxtail + bdx * adytail)) 1525 | + cdztail * (adx * bdy - ady * bdx)); 1526 | 1527 | if det >= errbound || -det >= errbound { 1528 | return det; 1529 | } 1530 | 1531 | let at_blen; 1532 | let at_clen; 1533 | let at_b; 1534 | let at_c; 1535 | if adxtail == 0.0 { 1536 | if adytail == 0.0 { 1537 | at_b = [0.; 4]; 1538 | at_blen = 1; 1539 | at_c = [0.; 4]; 1540 | at_clen = 1; 1541 | } else { 1542 | let negate = -adytail; 1543 | let [at_b0, at_blarge] = two_product(negate, bdx); 1544 | at_b = [at_b0, at_blarge, 0., 0.]; 1545 | at_blen = 2; 1546 | let [at_c0, at_clarge] = two_product(adytail, cdx); 1547 | at_c = [at_c0, at_clarge, 0., 0.]; 1548 | at_clen = 2; 1549 | } 1550 | } else if adytail == 0.0 { 1551 | let [at_b0, at_blarge] = two_product(adxtail, bdy); 1552 | at_b = [at_b0, at_blarge, 0., 0.]; 1553 | at_blen = 2; 1554 | let negate = -adxtail; 1555 | let [at_c0, at_clarge] = two_product(negate, cdy); 1556 | at_c = [at_c0, at_clarge, 0., 0.]; 1557 | at_clen = 2; 1558 | } else { 1559 | let [adxt_bdy0, adxt_bdy1] = two_product(adxtail, bdy); 1560 | let [adyt_bdx0, adyt_bdx1] = two_product(adytail, bdx); 1561 | at_b = two_two_diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0); 1562 | at_blen = 4; 1563 | let [adyt_cdx0, adyt_cdx1] = two_product(adytail, cdx); 1564 | let [adxt_cdy0, adxt_cdy1] = two_product(adxtail, cdy); 1565 | at_c = two_two_diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0); 1566 | at_clen = 4; 1567 | } 1568 | let bt_clen; 1569 | let bt_alen; 1570 | let bt_c; 1571 | let bt_a; 1572 | if bdxtail == 0.0 { 1573 | if bdytail == 0.0 { 1574 | bt_c = [0.0; 4]; 1575 | bt_clen = 1; 1576 | bt_a = [0.0; 4]; 1577 | bt_alen = 1; 1578 | } else { 1579 | let negate = -bdytail; 1580 | let [bt_c0, bt_clarge] = two_product(negate, cdx); 1581 | bt_c = [bt_c0, bt_clarge, 0., 0.]; 1582 | bt_clen = 2; 1583 | let [bt_a0, bt_alarge] = two_product(bdytail, adx); 1584 | bt_a = [bt_a0, bt_alarge, 0., 0.]; 1585 | bt_alen = 2; 1586 | } 1587 | } else if bdytail == 0.0 { 1588 | let [bt_c0, bt_clarge] = two_product(bdxtail, cdy); 1589 | bt_c = [bt_c0, bt_clarge, 0., 0.]; 1590 | bt_clen = 2; 1591 | let negate = -bdxtail; 1592 | let [bt_a0, bt_alarge] = two_product(negate, ady); 1593 | bt_a = [bt_a0, bt_alarge, 0., 0.]; 1594 | bt_alen = 2 1595 | } else { 1596 | let [bdxt_cdy0, bdxt_cdy1] = two_product(bdxtail, cdy); 1597 | let [bdyt_cdx0, bdyt_cdx1] = two_product(bdytail, cdx); 1598 | bt_c = two_two_diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0); 1599 | bt_clen = 4; 1600 | let [bdyt_adx0, bdyt_adx1] = two_product(bdytail, adx); 1601 | let [bdxt_ady0, bdxt_ady1] = two_product(bdxtail, ady); 1602 | bt_a = two_two_diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0); 1603 | bt_alen = 4; 1604 | } 1605 | let ct_alen; 1606 | let ct_blen; 1607 | let ct_a; 1608 | let ct_b; 1609 | if cdxtail == 0.0 { 1610 | if cdytail == 0.0 { 1611 | ct_a = [0.; 4]; 1612 | ct_alen = 1; 1613 | ct_b = [0.; 4]; 1614 | ct_blen = 1; 1615 | } else { 1616 | let negate = -cdytail; 1617 | let [ct_a0, ct_alarge] = two_product(negate, adx); 1618 | ct_a = [ct_a0, ct_alarge, 0., 0.]; 1619 | ct_alen = 2; 1620 | let [ct_b0, ct_blarge] = two_product(cdytail, bdx); 1621 | ct_b = [ct_b0, ct_blarge, 0., 0.]; 1622 | ct_blen = 2; 1623 | } 1624 | } else if cdytail == 0.0 { 1625 | let [ct_a0, ct_alarge] = two_product(cdxtail, ady); 1626 | ct_a = [ct_a0, ct_alarge, 0., 0.]; 1627 | ct_alen = 2; 1628 | let negate = -cdxtail; 1629 | let [ct_b0, ct_blarge] = two_product(negate, bdy); 1630 | ct_b = [ct_b0, ct_blarge, 0., 0.]; 1631 | ct_blen = 2; 1632 | } else { 1633 | let [cdxt_ady0, cdxt_ady1] = two_product(cdxtail, ady); 1634 | let [cdyt_adx0, cdyt_adx1] = two_product(cdytail, adx); 1635 | ct_a = two_two_diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0); 1636 | ct_alen = 4; 1637 | let [cdyt_bdx0, cdyt_bdx1] = two_product(cdytail, bdx); 1638 | let [cdxt_bdy0, cdxt_bdy1] = two_product(cdxtail, bdy); 1639 | ct_b = two_two_diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0); 1640 | ct_blen = 4; 1641 | } 1642 | 1643 | let mut fin2 = [0.; 192]; 1644 | 1645 | let mut w = [0.; 16]; 1646 | 1647 | let mut bct = [0.; 8]; 1648 | let bctlen = fast_expansion_sum_zeroelim(&bt_c[..bt_clen], &ct_b[..ct_blen], &mut bct); 1649 | let wlength = scale_expansion_zeroelim(&bct[..bctlen], adz, &mut w); 1650 | finlength = fast_expansion_sum_zeroelim(&fin1[..finlength], &w[..wlength], &mut fin2); 1651 | 1652 | let mut cat = [0.; 8]; 1653 | let catlen = fast_expansion_sum_zeroelim(&ct_a[..ct_alen], &at_c[..at_clen], &mut cat); 1654 | let wlength = scale_expansion_zeroelim(&cat[..catlen], bdz, &mut w); 1655 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &w[..wlength], &mut fin1); 1656 | 1657 | let mut abt = [0.; 8]; 1658 | let abtlen = fast_expansion_sum_zeroelim(&at_b[..at_blen], &bt_a[..bt_alen], &mut abt); 1659 | let wlength = scale_expansion_zeroelim(&abt[..abtlen], cdz, &mut w); 1660 | finlength = fast_expansion_sum_zeroelim(&fin1[..finlength], &w[..wlength], &mut fin2); 1661 | 1662 | let mut v = [0.; 12]; 1663 | 1664 | // TODO: replace these swaps with destructuring assignment when it is stable; 1665 | // https://github.com/rust-lang/rfcs/pull/2909 1666 | let (mut fin1, fin2) = if adztail != 0.0 { 1667 | let vlength = scale_expansion_zeroelim(&bc, adztail, &mut v); 1668 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &v[..vlength], &mut fin1); 1669 | (fin2, fin1) 1670 | } else { 1671 | (fin1, fin2) 1672 | }; 1673 | let (mut fin1, fin2) = if bdztail != 0.0 { 1674 | let vlength = scale_expansion_zeroelim(&ca, bdztail, &mut v); 1675 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &v[..vlength], &mut fin1); 1676 | (fin2, fin1) 1677 | } else { 1678 | (fin1, fin2) 1679 | }; 1680 | let (mut fin1, fin2) = if cdztail != 0.0 { 1681 | let vlength = scale_expansion_zeroelim(&ab, cdztail, &mut v); 1682 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &v[..vlength], &mut fin1); 1683 | (fin2, fin1) 1684 | } else { 1685 | (fin1, fin2) 1686 | }; 1687 | let (mut fin1, fin2) = if adxtail != 0.0 { 1688 | let (mut fin1, fin2) = if bdytail != 0.0 { 1689 | let [adxt_bdyt0, adxt_bdyt1] = two_product(adxtail, bdytail); 1690 | let u = two_one_product(adxt_bdyt1, adxt_bdyt0, cdz); 1691 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1692 | let (mut fin1, fin2) = (fin2, fin1); 1693 | if cdztail != 0.0 { 1694 | let u = two_one_product(adxt_bdyt1, adxt_bdyt0, cdztail); 1695 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1696 | (fin2, fin1) 1697 | } else { 1698 | (fin1, fin2) 1699 | } 1700 | } else { 1701 | (fin1, fin2) 1702 | }; 1703 | if cdytail != 0.0 { 1704 | let negate = -adxtail; 1705 | let [adxt_cdyt0, adxt_cdyt1] = two_product(negate, cdytail); 1706 | let u = two_one_product(adxt_cdyt1, adxt_cdyt0, bdz); 1707 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1708 | let (mut fin1, fin2) = (fin2, fin1); 1709 | if bdztail != 0.0 { 1710 | let u = two_one_product(adxt_cdyt1, adxt_cdyt0, bdztail); 1711 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1712 | (fin2, fin1) 1713 | } else { 1714 | (fin1, fin2) 1715 | } 1716 | } else { 1717 | (fin1, fin2) 1718 | } 1719 | } else { 1720 | (fin1, fin2) 1721 | }; 1722 | let (mut fin1, fin2) = if bdxtail != 0.0 { 1723 | let (mut fin1, fin2) = if cdytail != 0.0 { 1724 | let [bdxt_cdyt0, bdxt_cdyt1] = two_product(bdxtail, cdytail); 1725 | let u = two_one_product(bdxt_cdyt1, bdxt_cdyt0, adz); 1726 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1727 | let (mut fin1, fin2) = (fin2, fin1); 1728 | if adztail != 0.0 { 1729 | let u = two_one_product(bdxt_cdyt1, bdxt_cdyt0, adztail); 1730 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1731 | (fin2, fin1) 1732 | } else { 1733 | (fin1, fin2) 1734 | } 1735 | } else { 1736 | (fin1, fin2) 1737 | }; 1738 | if adytail != 0.0 { 1739 | let negate = -bdxtail; 1740 | let [bdxt_adyt0, bdxt_adyt1] = two_product(negate, adytail); 1741 | let u = two_one_product(bdxt_adyt1, bdxt_adyt0, cdz); 1742 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1743 | let (mut fin1, fin2) = (fin2, fin1); 1744 | if cdztail != 0.0 { 1745 | let u = two_one_product(bdxt_adyt1, bdxt_adyt0, cdztail); 1746 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1747 | (fin2, fin1) 1748 | } else { 1749 | (fin1, fin2) 1750 | } 1751 | } else { 1752 | (fin1, fin2) 1753 | } 1754 | } else { 1755 | (fin1, fin2) 1756 | }; 1757 | let (mut fin1, fin2) = if cdxtail != 0.0 { 1758 | let (mut fin1, fin2) = if adytail != 0.0 { 1759 | let [cdxt_adyt0, cdxt_adyt1] = two_product(cdxtail, adytail); 1760 | let u = two_one_product(cdxt_adyt1, cdxt_adyt0, bdz); 1761 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1762 | let (mut fin1, fin2) = (fin2, fin1); 1763 | if bdztail != 0.0 { 1764 | let u = two_one_product(cdxt_adyt1, cdxt_adyt0, bdztail); 1765 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1766 | (fin2, fin1) 1767 | } else { 1768 | (fin1, fin2) 1769 | } 1770 | } else { 1771 | (fin1, fin2) 1772 | }; 1773 | if bdytail != 0.0 { 1774 | let negate = -cdxtail; 1775 | let [cdxt_bdyt0, cdxt_bdyt1] = two_product(negate, bdytail); 1776 | let u = two_one_product(cdxt_bdyt1, cdxt_bdyt0, adz); 1777 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1778 | let (mut fin1, fin2) = (fin2, fin1); 1779 | if adztail != 0.0 { 1780 | let u = two_one_product(cdxt_bdyt1, cdxt_bdyt0, adztail); 1781 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &u, &mut fin1); 1782 | (fin2, fin1) 1783 | } else { 1784 | (fin1, fin2) 1785 | } 1786 | } else { 1787 | (fin1, fin2) 1788 | } 1789 | } else { 1790 | (fin1, fin2) 1791 | }; 1792 | let (mut fin1, fin2) = if adztail != 0.0 { 1793 | let wlength = scale_expansion_zeroelim(&bct[..bctlen], adztail, &mut w); 1794 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &w[..wlength], &mut fin1); 1795 | (fin2, fin1) 1796 | } else { 1797 | (fin1, fin2) 1798 | }; 1799 | let (mut fin1, fin2) = if bdztail != 0.0 { 1800 | let wlength = scale_expansion_zeroelim(&cat[..catlen], bdztail, &mut w); 1801 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &w[..wlength], &mut fin1); 1802 | (fin2, fin1) 1803 | } else { 1804 | (fin1, fin2) 1805 | }; 1806 | let fin2 = if cdztail != 0.0 { 1807 | let wlength = scale_expansion_zeroelim(&abt[..abtlen], cdztail, &mut w); 1808 | finlength = fast_expansion_sum_zeroelim(&fin2[..finlength], &w[..wlength], &mut fin1); 1809 | fin1 1810 | } else { 1811 | fin2 1812 | }; 1813 | fin2[finlength - 1] 1814 | } 1815 | 1816 | /** 1817 | * Adaptive exact 3D orientation test. Robust. 1818 | * 1819 | * Returns a positive value if the point `pd` lies below the 1820 | * plane passing through `pa`, `pb`, and `pc`; "below" is defined so 1821 | * that `pa`, `pb`, and `pc` appear in counterclockwise order when 1822 | * viewed from above the plane. Returns a negative value if 1823 | * pd lies above the plane. Returns zero if the points are 1824 | * coplanar. The result is also a rough approximation of six 1825 | * times the signed volume of the tetrahedron defined by the 1826 | * four points. 1827 | * 1828 | * The result returned is the determinant of a matrix. 1829 | * This determinant is computed adaptively, in the sense that exact 1830 | * arithmetic is used only to the degree it is needed to ensure that the 1831 | * returned value has the correct sign. Hence, orient3d() is usually quite 1832 | * fast, but will run more slowly when the input points are coplanar or 1833 | * nearly so. 1834 | */ 1835 | #[inline] 1836 | pub fn orient3d(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3]) -> f64 { 1837 | let adx = pa[0] - pd[0]; 1838 | let bdx = pb[0] - pd[0]; 1839 | let cdx = pc[0] - pd[0]; 1840 | let ady = pa[1] - pd[1]; 1841 | let bdy = pb[1] - pd[1]; 1842 | let cdy = pc[1] - pd[1]; 1843 | let adz = pa[2] - pd[2]; 1844 | let bdz = pb[2] - pd[2]; 1845 | let cdz = pc[2] - pd[2]; 1846 | let bdxcdy = bdx * cdy; 1847 | let cdxbdy = cdx * bdy; 1848 | let cdxady = cdx * ady; 1849 | let adxcdy = adx * cdy; 1850 | let adxbdy = adx * bdy; 1851 | let bdxady = bdx * ady; 1852 | let det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady); 1853 | let permanent = (abs(bdxcdy) + abs(cdxbdy)) * abs(adz) 1854 | + (abs(cdxady) + abs(adxcdy)) * abs(bdz) 1855 | + (abs(adxbdy) + abs(bdxady)) * abs(cdz); 1856 | let errbound = PARAMS.o3derrbound_a * permanent; 1857 | if det > errbound || -det > errbound { 1858 | return det; 1859 | } 1860 | orient3dadapt(pa, pb, pc, pd, permanent) 1861 | } 1862 | 1863 | /* ****************************************************************************/ 1864 | /* */ 1865 | /* incircle_fast() Approximate 2D incircle test. Nonrobust. */ 1866 | /* incircle_exact() Exact 2D incircle test. Robust. */ 1867 | /* incircle_slow() Another exact 2D incircle test. Robust. */ 1868 | /* incircle() Adaptive exact 2D incircle test. Robust. */ 1869 | /* */ 1870 | /* Return a positive value if the point pd lies inside the */ 1871 | /* circle passing through pa, pb, and pc; a negative value if */ 1872 | /* it lies outside; and zero if the four points are cocircular.*/ 1873 | /* The points pa, pb, and pc must be in counterclockwise */ 1874 | /* order, or the sign of the result will be reversed. */ 1875 | /* */ 1876 | /* Only the first and last routine should be used; the middle two are for */ 1877 | /* timings. */ 1878 | /* */ 1879 | /* The last three use exact arithmetic to ensure a correct answer. The */ 1880 | /* result returned is the determinant of a matrix. In incircle() only, */ 1881 | /* this determinant is computed adaptively, in the sense that exact */ 1882 | /* arithmetic is used only to the degree it is needed to ensure that the */ 1883 | /* returned value has the correct sign. Hence, incircle() is usually quite */ 1884 | /* fast, but will run more slowly when the input points are cocircular or */ 1885 | /* nearly so. */ 1886 | /* */ 1887 | /* ****************************************************************************/ 1888 | 1889 | /// Approximate 2D incircle test. Non-robust version of [`incircle`]. 1890 | #[inline] 1891 | pub fn incircle_fast(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2], pd: [f64; 2]) -> f64 { 1892 | let adx = pa[0] - pd[0]; 1893 | let ady = pa[1] - pd[1]; 1894 | let bdx = pb[0] - pd[0]; 1895 | let bdy = pb[1] - pd[1]; 1896 | let cdx = pc[0] - pd[0]; 1897 | let cdy = pc[1] - pd[1]; 1898 | let abdet = adx * bdy - bdx * ady; 1899 | let bcdet = bdx * cdy - cdx * bdy; 1900 | let cadet = cdx * ady - adx * cdy; 1901 | let alift = adx * adx + ady * ady; 1902 | let blift = bdx * bdx + bdy * bdy; 1903 | let clift = cdx * cdx + cdy * cdy; 1904 | alift * bcdet + blift * cadet + clift * abdet 1905 | } 1906 | 1907 | #[inline] 1908 | pub fn incircle_exact(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2], pd: [f64; 2]) -> f64 { 1909 | let [axby0, axby1] = two_product(pa[0], pb[1]); 1910 | let [bxay0, bxay1] = two_product(pb[0], pa[1]); 1911 | let ab = two_two_diff(axby1, axby0, bxay1, bxay0); 1912 | let [bxcy0, bxcy1] = two_product(pb[0], pc[1]); 1913 | let [cxby0, cxby1] = two_product(pc[0], pb[1]); 1914 | let bc = two_two_diff(bxcy1, bxcy0, cxby1, cxby0); 1915 | let [cxdy0, cxdy1] = two_product(pc[0], pd[1]); 1916 | let [dxcy0, dxcy1] = two_product(pd[0], pc[1]); 1917 | let cd = two_two_diff(cxdy1, cxdy0, dxcy1, dxcy0); 1918 | let [dxay0, dxay1] = two_product(pd[0], pa[1]); 1919 | let [axdy0, axdy1] = two_product(pa[0], pd[1]); 1920 | let da = two_two_diff(dxay1, dxay0, axdy1, axdy0); 1921 | let [axcy0, axcy1] = two_product(pa[0], pc[1]); 1922 | let [cxay0, cxay1] = two_product(pc[0], pa[1]); 1923 | let mut ac = two_two_diff(axcy1, axcy0, cxay1, cxay0); 1924 | let [bxdy0, bxdy1] = two_product(pb[0], pd[1]); 1925 | let [dxby0, dxby1] = two_product(pd[0], pb[1]); 1926 | let mut bd = two_two_diff(bxdy1, bxdy0, dxby1, dxby0); 1927 | let mut temp8 = [0.; 8]; 1928 | let templen = fast_expansion_sum_zeroelim(&cd, &da, &mut temp8); 1929 | let mut cda = [0.; 12]; 1930 | let cdalen = fast_expansion_sum_zeroelim(&temp8[..templen], &ac, &mut cda); 1931 | let templen = fast_expansion_sum_zeroelim(&da, &ab, &mut temp8); 1932 | let mut dab = [0.; 12]; 1933 | let dablen = fast_expansion_sum_zeroelim(&temp8[..templen], &bd, &mut dab); 1934 | bd.iter_mut().for_each(|x| *x = -*x); 1935 | ac.iter_mut().for_each(|x| *x = -*x); 1936 | let templen = fast_expansion_sum_zeroelim(&ab, &bc, &mut temp8); 1937 | let mut abc = [0.; 12]; 1938 | let abclen = fast_expansion_sum_zeroelim(&temp8[..templen], &ac, &mut abc); 1939 | let templen = fast_expansion_sum_zeroelim(&bc, &cd, &mut temp8); 1940 | let mut bcd = [0.; 12]; 1941 | let bcdlen = fast_expansion_sum_zeroelim(&temp8[..templen], &bd, &mut bcd); 1942 | let mut det24x = [0.; 24]; 1943 | let xlen = scale_expansion_zeroelim(&bcd[..bcdlen], pa[0], &mut det24x); 1944 | let mut det48x = [0.; 48]; 1945 | let xlen = scale_expansion_zeroelim(&det24x[..xlen], pa[0], &mut det48x); 1946 | let mut det24y = [0.; 24]; 1947 | let ylen = scale_expansion_zeroelim(&bcd[..bcdlen], pa[1], &mut det24y); 1948 | let mut det48y = [0.; 48]; 1949 | let ylen = scale_expansion_zeroelim(&det24y[..ylen], pa[1], &mut det48y); 1950 | let mut adet = [0.; 96]; 1951 | let alen = fast_expansion_sum_zeroelim(&det48x[..xlen], &det48y[..ylen], &mut adet); 1952 | let xlen = scale_expansion_zeroelim(&cda[..cdalen], pb[0], &mut det24x); 1953 | let xlen = scale_expansion_zeroelim(&det24x[..xlen], -pb[0], &mut det48x); 1954 | let ylen = scale_expansion_zeroelim(&cda[..cdalen], pb[1], &mut det24y); 1955 | let ylen = scale_expansion_zeroelim(&det24y[..ylen], -pb[1], &mut det48y); 1956 | let mut bdet = [0.; 96]; 1957 | let blen = fast_expansion_sum_zeroelim(&det48x[..xlen], &det48y[..ylen], &mut bdet); 1958 | let xlen = scale_expansion_zeroelim(&dab[..dablen], pc[0], &mut det24x); 1959 | let xlen = scale_expansion_zeroelim(&det24x[..xlen], pc[0], &mut det48x); 1960 | let ylen = scale_expansion_zeroelim(&dab[..dablen], pc[1], &mut det24y); 1961 | let ylen = scale_expansion_zeroelim(&det24y[..ylen], pc[1], &mut det48y); 1962 | let mut cdet = [0.; 96]; 1963 | let clen = fast_expansion_sum_zeroelim(&det48x[..xlen], &det48y[..ylen], &mut cdet); 1964 | let xlen = scale_expansion_zeroelim(&abc[..abclen], pd[0], &mut det24x); 1965 | let xlen = scale_expansion_zeroelim(&det24x[..xlen], -pd[0], &mut det48x); 1966 | let ylen = scale_expansion_zeroelim(&abc[..abclen], pd[1], &mut det24y); 1967 | let ylen = scale_expansion_zeroelim(&det24y[..ylen], -pd[1], &mut det48y); 1968 | let mut ddet = [0.; 96]; 1969 | let dlen = fast_expansion_sum_zeroelim(&det48x[..xlen], &det48y[..ylen], &mut ddet); 1970 | let mut abdet = [0.; 192]; 1971 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 1972 | let mut cddet = [0.; 192]; 1973 | let cdlen = fast_expansion_sum_zeroelim(&cdet[..clen], &ddet[..dlen], &mut cddet); 1974 | let mut deter = [0.; 384]; 1975 | let deterlen = fast_expansion_sum_zeroelim(&abdet[..ablen], &cddet[..cdlen], &mut deter); 1976 | deter[deterlen - 1] 1977 | } 1978 | 1979 | #[inline] 1980 | pub fn incircle_slow(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2], pd: [f64; 2]) -> f64 { 1981 | let [adxtail, adx] = two_diff(pa[0], pd[0]); 1982 | let [adytail, ady] = two_diff(pa[1], pd[1]); 1983 | let [bdxtail, bdx] = two_diff(pb[0], pd[0]); 1984 | let [bdytail, bdy] = two_diff(pb[1], pd[1]); 1985 | let [cdxtail, cdx] = two_diff(pc[0], pd[0]); 1986 | let [cdytail, cdy] = two_diff(pc[1], pd[1]); 1987 | let axby = two_two_product(adx, adxtail, bdy, bdytail); 1988 | let negate = -ady; 1989 | let negatetail = -adytail; 1990 | let bxay = two_two_product(bdx, bdxtail, negate, negatetail); 1991 | let bxcy = two_two_product(bdx, bdxtail, cdy, cdytail); 1992 | let negate = -bdy; 1993 | let negatetail = -bdytail; 1994 | let cxby = two_two_product(cdx, cdxtail, negate, negatetail); 1995 | let cxay = two_two_product(cdx, cdxtail, ady, adytail); 1996 | let negate = -cdy; 1997 | let negatetail = -cdytail; 1998 | let axcy = two_two_product(adx, adxtail, negate, negatetail); 1999 | let mut temp16 = [0.; 16]; 2000 | let temp16len = fast_expansion_sum_zeroelim(&bxcy, &cxby, &mut temp16); 2001 | let mut detx = [0.; 32]; 2002 | let xlen = scale_expansion_zeroelim(&temp16[..temp16len], adx, &mut detx); 2003 | let mut detxx = [0.; 64]; 2004 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], adx, &mut detxx); 2005 | let mut detxt = [0.; 32]; 2006 | let xtlen = scale_expansion_zeroelim(&temp16[..temp16len], adxtail, &mut detxt); 2007 | let mut detxxt = [0.; 64]; 2008 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], adx, &mut detxxt); 2009 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 2010 | let mut detxtxt = [0.; 64]; 2011 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], adxtail, &mut detxtxt); 2012 | let mut x1 = [0.; 128]; 2013 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 2014 | let mut x2 = [0.; 192]; 2015 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 2016 | let mut dety = [0.; 32]; 2017 | let ylen = scale_expansion_zeroelim(&temp16[..temp16len], ady, &mut dety); 2018 | let mut detyy = [0.; 64]; 2019 | let yylen = scale_expansion_zeroelim(&dety[..ylen], ady, &mut detyy); 2020 | let mut detyt = [0.; 32]; 2021 | let ytlen = scale_expansion_zeroelim(&temp16[..temp16len], adytail, &mut detyt); 2022 | let mut detyyt = [0.; 64]; 2023 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], ady, &mut detyyt); 2024 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 2025 | let mut detytyt = [0.; 64]; 2026 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], adytail, &mut detytyt); 2027 | let mut y1 = [0.; 128]; 2028 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 2029 | let mut y2 = [0.; 192]; 2030 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 2031 | let mut adet = [0.; 384]; 2032 | let alen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut adet); 2033 | let temp16len = fast_expansion_sum_zeroelim(&cxay, &axcy, &mut temp16); 2034 | let xlen = scale_expansion_zeroelim(&temp16[..temp16len], bdx, &mut detx); 2035 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], bdx, &mut detxx); 2036 | let xtlen = scale_expansion_zeroelim(&temp16[..temp16len], bdxtail, &mut detxt); 2037 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], bdx, &mut detxxt); 2038 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 2039 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], bdxtail, &mut detxtxt); 2040 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 2041 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 2042 | let ylen = scale_expansion_zeroelim(&temp16[..temp16len], bdy, &mut dety); 2043 | let yylen = scale_expansion_zeroelim(&dety[..ylen], bdy, &mut detyy); 2044 | let ytlen = scale_expansion_zeroelim(&temp16[..temp16len], bdytail, &mut detyt); 2045 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], bdy, &mut detyyt); 2046 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 2047 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], bdytail, &mut detytyt); 2048 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 2049 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 2050 | let mut bdet = [0.; 384]; 2051 | let blen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut bdet); 2052 | let temp16len = fast_expansion_sum_zeroelim(&axby, &bxay, &mut temp16); 2053 | let xlen = scale_expansion_zeroelim(&temp16[..temp16len], cdx, &mut detx); 2054 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], cdx, &mut detxx); 2055 | let xtlen = scale_expansion_zeroelim(&temp16[..temp16len], cdxtail, &mut detxt); 2056 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], cdx, &mut detxxt); 2057 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 2058 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], cdxtail, &mut detxtxt); 2059 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 2060 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 2061 | let ylen = scale_expansion_zeroelim(&temp16[..temp16len], cdy, &mut dety); 2062 | let yylen = scale_expansion_zeroelim(&dety[..ylen], cdy, &mut detyy); 2063 | let ytlen = scale_expansion_zeroelim(&temp16[..temp16len], cdytail, &mut detyt); 2064 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], cdy, &mut detyyt); 2065 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 2066 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], cdytail, &mut detytyt); 2067 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 2068 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 2069 | let mut cdet = [0.; 384]; 2070 | let clen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut cdet); 2071 | let mut abdet = [0.; 768]; 2072 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 2073 | let mut deter = [0.; 1152]; 2074 | let deterlen = fast_expansion_sum_zeroelim(&abdet[..ablen], &cdet[..clen], &mut deter); 2075 | deter[deterlen - 1] 2076 | } 2077 | 2078 | #[inline] 2079 | pub fn incircleadapt( 2080 | pa: [f64; 2], 2081 | pb: [f64; 2], 2082 | pc: [f64; 2], 2083 | pd: [f64; 2], 2084 | permanent: f64, 2085 | ) -> f64 { 2086 | let mut axbc = [0.; 8]; 2087 | let mut axxbc = [0.; 16]; 2088 | let mut aybc = [0.; 8]; 2089 | let mut ayybc = [0.; 16]; 2090 | let mut adet = [0.; 32]; 2091 | let mut bxca = [0.; 8]; 2092 | let mut bxxca = [0.; 16]; 2093 | let mut byca = [0.; 8]; 2094 | let mut byyca = [0.; 16]; 2095 | let mut bdet = [0.; 32]; 2096 | let mut cxab = [0.; 8]; 2097 | let mut cxxab = [0.; 16]; 2098 | let mut cyab = [0.; 8]; 2099 | let mut cyyab = [0.; 16]; 2100 | let mut cdet = [0.; 32]; 2101 | let mut abdet = [0.; 64]; 2102 | let mut fin1 = [0.; 1152]; 2103 | let mut fin2 = [0.; 1152]; 2104 | let mut finnow: &mut [f64]; 2105 | let mut finother: &mut [f64]; 2106 | let mut temp8 = [0.; 8]; 2107 | let mut temp16a = [0.; 16]; 2108 | let mut temp16b = [0.; 16]; 2109 | let mut temp16c = [0.; 16]; 2110 | let mut temp32a = [0.; 32]; 2111 | let mut temp32b = [0.; 32]; 2112 | let mut temp48 = [0.; 48]; 2113 | let mut temp64 = [0.; 64]; 2114 | let mut axtbb = [0.; 8]; 2115 | let mut axtcc = [0.; 8]; 2116 | let mut aytbb = [0.; 8]; 2117 | let mut aytcc = [0.; 8]; 2118 | let mut bxtaa = [0.; 8]; 2119 | let mut bxtcc = [0.; 8]; 2120 | let mut bytaa = [0.; 8]; 2121 | let mut bytcc = [0.; 8]; 2122 | let mut cxtaa = [0.; 8]; 2123 | let mut cxtbb = [0.; 8]; 2124 | let mut cytaa = [0.; 8]; 2125 | let mut cytbb = [0.; 8]; 2126 | let mut axtbct = [0.; 16]; 2127 | let mut aytbct = [0.; 16]; 2128 | let mut bxtcat = [0.; 16]; 2129 | let mut bytcat = [0.; 16]; 2130 | let mut cxtabt = [0.; 16]; 2131 | let mut cytabt = [0.; 16]; 2132 | let mut axtbctt = [0.; 8]; 2133 | let mut aytbctt = [0.; 8]; 2134 | let mut bxtcatt = [0.; 8]; 2135 | let mut bytcatt = [0.; 8]; 2136 | let mut cxtabtt = [0.; 8]; 2137 | let mut cytabtt = [0.; 8]; 2138 | let adx = pa[0] - pd[0]; 2139 | let bdx = pb[0] - pd[0]; 2140 | let cdx = pc[0] - pd[0]; 2141 | let ady = pa[1] - pd[1]; 2142 | let bdy = pb[1] - pd[1]; 2143 | let cdy = pc[1] - pd[1]; 2144 | let [bdxcdy0, bdxcdy1] = two_product(bdx, cdy); 2145 | let [cdxbdy0, cdxbdy1] = two_product(cdx, bdy); 2146 | let bc = two_two_diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0); 2147 | let axbclen = scale_expansion_zeroelim(&bc, adx, &mut axbc); 2148 | let axxbclen = scale_expansion_zeroelim(&axbc[..axbclen], adx, &mut axxbc); 2149 | let aybclen = scale_expansion_zeroelim(&bc, ady, &mut aybc); 2150 | let ayybclen = scale_expansion_zeroelim(&aybc[..aybclen], ady, &mut ayybc); 2151 | let alen = fast_expansion_sum_zeroelim(&axxbc[..axxbclen], &ayybc[..ayybclen], &mut adet); 2152 | let [cdxady0, cdxady1] = two_product(cdx, ady); 2153 | let [adxcdy0, adxcdy1] = two_product(adx, cdy); 2154 | let ca = two_two_diff(cdxady1, cdxady0, adxcdy1, adxcdy0); 2155 | let bxcalen = scale_expansion_zeroelim(&ca, bdx, &mut bxca); 2156 | let bxxcalen = scale_expansion_zeroelim(&bxca[..bxcalen], bdx, &mut bxxca); 2157 | let bycalen = scale_expansion_zeroelim(&ca, bdy, &mut byca); 2158 | let byycalen = scale_expansion_zeroelim(&byca[..bycalen], bdy, &mut byyca); 2159 | let blen = fast_expansion_sum_zeroelim(&bxxca[..bxxcalen], &byyca[..byycalen], &mut bdet); 2160 | let [adxbdy0, adxbdy1] = two_product(adx, bdy); 2161 | let [bdxady0, bdxady1] = two_product(bdx, ady); 2162 | let ab = two_two_diff(adxbdy1, adxbdy0, bdxady1, bdxady0); 2163 | let cxablen = scale_expansion_zeroelim(&ab, cdx, &mut cxab); 2164 | let cxxablen = scale_expansion_zeroelim(&cxab[..cxablen], cdx, &mut cxxab); 2165 | let cyablen = scale_expansion_zeroelim(&ab, cdy, &mut cyab); 2166 | let cyyablen = scale_expansion_zeroelim(&cyab[..cyablen], cdy, &mut cyyab); 2167 | let clen = fast_expansion_sum_zeroelim(&cxxab[..cxxablen], &cyyab[..cyyablen], &mut cdet); 2168 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 2169 | let mut finlength = fast_expansion_sum_zeroelim(&abdet[..ablen], &cdet[..clen], &mut fin1); 2170 | let mut det: f64 = fin1[..finlength].iter().sum(); 2171 | let errbound = PARAMS.iccerrbound_b * permanent; 2172 | if det >= errbound || -det >= errbound { 2173 | return det; 2174 | } 2175 | let adxtail = two_diff_tail(pa[0], pd[0], adx); 2176 | let adytail = two_diff_tail(pa[1], pd[1], ady); 2177 | let bdxtail = two_diff_tail(pb[0], pd[0], bdx); 2178 | let bdytail = two_diff_tail(pb[1], pd[1], bdy); 2179 | let cdxtail = two_diff_tail(pc[0], pd[0], cdx); 2180 | let cdytail = two_diff_tail(pc[1], pd[1], cdy); 2181 | if adxtail == 0.0 2182 | && bdxtail == 0.0 2183 | && cdxtail == 0.0 2184 | && adytail == 0.0 2185 | && bdytail == 0.0 2186 | && cdytail == 0.0 2187 | { 2188 | return det; 2189 | } 2190 | let errbound = PARAMS.iccerrbound_c * permanent + PARAMS.resulterrbound * abs(det); 2191 | det += (adx * adx + ady * ady) 2192 | * (bdx * cdytail + cdy * bdxtail - (bdy * cdxtail + cdx * bdytail)) 2193 | + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx) 2194 | + ((bdx * bdx + bdy * bdy) 2195 | * (cdx * adytail + ady * cdxtail - (cdy * adxtail + adx * cdytail)) 2196 | + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) 2197 | + ((cdx * cdx + cdy * cdy) 2198 | * (adx * bdytail + bdy * adxtail - (ady * bdxtail + bdx * adytail)) 2199 | + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); 2200 | if det >= errbound || -det >= errbound { 2201 | return det; 2202 | } 2203 | finnow = &mut fin1; 2204 | finother = &mut fin2; 2205 | let aa = if bdxtail != 0.0 || bdytail != 0.0 || cdxtail != 0.0 || cdytail != 0.0 { 2206 | let [adxadx0, adxadx1] = square(adx); 2207 | let [adyady0, adyady1] = square(ady); 2208 | two_two_sum(adxadx1, adxadx0, adyady1, adyady0) 2209 | } else { 2210 | [0.; 4] 2211 | }; 2212 | let bb = if cdxtail != 0.0 || cdytail != 0.0 || adxtail != 0.0 || adytail != 0.0 { 2213 | let [bdxbdx0, bdxbdx1] = square(bdx); 2214 | let [bdybdy0, bdybdy1] = square(bdy); 2215 | two_two_sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0) 2216 | } else { 2217 | [0.; 4] 2218 | }; 2219 | let cc = if adxtail != 0.0 || adytail != 0.0 || bdxtail != 0.0 || bdytail != 0.0 { 2220 | let [cdxcdx0, cdxcdx1] = square(cdx); 2221 | let [cdycdy0, cdycdy1] = square(cdy); 2222 | two_two_sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0) 2223 | } else { 2224 | [0.; 4] 2225 | }; 2226 | let mut axtbclen = 8; 2227 | let mut axtbc = [0.; 8]; 2228 | if adxtail != 0.0 { 2229 | axtbclen = scale_expansion_zeroelim(&bc, adxtail, &mut axtbc); 2230 | let temp16alen = scale_expansion_zeroelim(&axtbc[..axtbclen], 2.0 * adx, &mut temp16a); 2231 | let axtcclen = scale_expansion_zeroelim(&cc, adxtail, &mut axtcc); 2232 | let temp16blen = scale_expansion_zeroelim(&axtcc[..axtcclen], bdy, &mut temp16b); 2233 | let axtbblen = scale_expansion_zeroelim(&bb, adxtail, &mut axtbb); 2234 | let temp16clen = scale_expansion_zeroelim(&axtbb[..axtbblen], -cdy, &mut temp16c); 2235 | let temp32alen = fast_expansion_sum_zeroelim( 2236 | &temp16a[..temp16alen], 2237 | &temp16b[..temp16blen], 2238 | &mut temp32a, 2239 | ); 2240 | let temp48len = fast_expansion_sum_zeroelim( 2241 | &temp16c[..temp16clen], 2242 | &temp32a[..temp32alen], 2243 | &mut temp48, 2244 | ); 2245 | finlength = 2246 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2247 | core::mem::swap(&mut finnow, &mut finother); 2248 | } 2249 | let mut aytbclen = 8; 2250 | let mut aytbc = [0.; 8]; 2251 | if adytail != 0.0 { 2252 | aytbclen = scale_expansion_zeroelim(&bc, adytail, &mut aytbc); 2253 | let temp16alen = scale_expansion_zeroelim(&aytbc[..aytbclen], 2.0 * ady, &mut temp16a); 2254 | let aytbblen = scale_expansion_zeroelim(&bb, adytail, &mut aytbb); 2255 | let temp16blen = scale_expansion_zeroelim(&aytbb[..aytbblen], cdx, &mut temp16b); 2256 | let aytcclen = scale_expansion_zeroelim(&cc, adytail, &mut aytcc); 2257 | let temp16clen = scale_expansion_zeroelim(&aytcc[..aytcclen], -bdx, &mut temp16c); 2258 | let temp32alen = fast_expansion_sum_zeroelim( 2259 | &temp16a[..temp16alen], 2260 | &temp16b[..temp16blen], 2261 | &mut temp32a, 2262 | ); 2263 | let temp48len = fast_expansion_sum_zeroelim( 2264 | &temp16c[..temp16clen], 2265 | &temp32a[..temp32alen], 2266 | &mut temp48, 2267 | ); 2268 | finlength = 2269 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2270 | core::mem::swap(&mut finnow, &mut finother); 2271 | } 2272 | let mut bxtcalen = 8; 2273 | let mut bxtca = [0.; 8]; 2274 | if bdxtail != 0.0 { 2275 | bxtcalen = scale_expansion_zeroelim(&ca, bdxtail, &mut bxtca); 2276 | let temp16alen = scale_expansion_zeroelim(&bxtca[..bxtcalen], 2.0 * bdx, &mut temp16a); 2277 | let bxtaalen = scale_expansion_zeroelim(&aa, bdxtail, &mut bxtaa); 2278 | let temp16blen = scale_expansion_zeroelim(&bxtaa[..bxtaalen], cdy, &mut temp16b); 2279 | let bxtcclen = scale_expansion_zeroelim(&cc, bdxtail, &mut bxtcc); 2280 | let temp16clen = scale_expansion_zeroelim(&bxtcc[..bxtcclen], -ady, &mut temp16c); 2281 | let temp32alen = fast_expansion_sum_zeroelim( 2282 | &temp16a[..temp16alen], 2283 | &temp16b[..temp16blen], 2284 | &mut temp32a, 2285 | ); 2286 | let temp48len = fast_expansion_sum_zeroelim( 2287 | &temp16c[..temp16clen], 2288 | &temp32a[..temp32alen], 2289 | &mut temp48, 2290 | ); 2291 | finlength = 2292 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2293 | core::mem::swap(&mut finnow, &mut finother); 2294 | } 2295 | let mut bytcalen = 8; 2296 | let mut bytca = [0.; 8]; 2297 | if bdytail != 0.0 { 2298 | bytcalen = scale_expansion_zeroelim(&ca, bdytail, &mut bytca); 2299 | let temp16alen = scale_expansion_zeroelim(&bytca[..bytcalen], 2.0 * bdy, &mut temp16a); 2300 | let bytcclen = scale_expansion_zeroelim(&cc, bdytail, &mut bytcc); 2301 | let temp16blen = scale_expansion_zeroelim(&bytcc[..bytcclen], adx, &mut temp16b); 2302 | let bytaalen = scale_expansion_zeroelim(&aa, bdytail, &mut bytaa); 2303 | let temp16clen = scale_expansion_zeroelim(&bytaa[..bytaalen], -cdx, &mut temp16c); 2304 | let temp32alen = fast_expansion_sum_zeroelim( 2305 | &temp16a[..temp16alen], 2306 | &temp16b[..temp16blen], 2307 | &mut temp32a, 2308 | ); 2309 | let temp48len = fast_expansion_sum_zeroelim( 2310 | &temp16c[..temp16clen], 2311 | &temp32a[..temp32alen], 2312 | &mut temp48, 2313 | ); 2314 | finlength = 2315 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2316 | core::mem::swap(&mut finnow, &mut finother); 2317 | } 2318 | let cxtablen = 8; 2319 | let mut cxtab = [0.; 8]; 2320 | if cdxtail != 0.0 { 2321 | let cxtablen = scale_expansion_zeroelim(&ab, cdxtail, &mut cxtab); 2322 | let temp16alen = scale_expansion_zeroelim(&cxtab[..cxtablen], 2.0 * cdx, &mut temp16a); 2323 | let cxtbblen = scale_expansion_zeroelim(&bb, cdxtail, &mut cxtbb); 2324 | let temp16blen = scale_expansion_zeroelim(&cxtbb[..cxtbblen], ady, &mut temp16b); 2325 | let cxtaalen = scale_expansion_zeroelim(&aa, cdxtail, &mut cxtaa); 2326 | let temp16clen = scale_expansion_zeroelim(&cxtaa[..cxtaalen], -bdy, &mut temp16c); 2327 | let temp32alen = fast_expansion_sum_zeroelim( 2328 | &temp16a[..temp16alen], 2329 | &temp16b[..temp16blen], 2330 | &mut temp32a, 2331 | ); 2332 | let temp48len = fast_expansion_sum_zeroelim( 2333 | &temp16c[..temp16clen], 2334 | &temp32a[..temp32alen], 2335 | &mut temp48, 2336 | ); 2337 | finlength = 2338 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2339 | core::mem::swap(&mut finnow, &mut finother); 2340 | } 2341 | let mut cytablen = 8; 2342 | let mut cytab = [0.; 8]; 2343 | if cdytail != 0.0 { 2344 | cytablen = scale_expansion_zeroelim(&ab, cdytail, &mut cytab); 2345 | let temp16alen = scale_expansion_zeroelim(&cytab[..cytablen], 2.0 * cdy, &mut temp16a); 2346 | let cytaalen = scale_expansion_zeroelim(&aa, cdytail, &mut cytaa); 2347 | let temp16blen = scale_expansion_zeroelim(&cytaa[..cytaalen], bdx, &mut temp16b); 2348 | let cytbblen = scale_expansion_zeroelim(&bb, cdytail, &mut cytbb); 2349 | let temp16clen = scale_expansion_zeroelim(&cytbb[..cytbblen], -adx, &mut temp16c); 2350 | let temp32alen = fast_expansion_sum_zeroelim( 2351 | &temp16a[..temp16alen], 2352 | &temp16b[..temp16blen], 2353 | &mut temp32a, 2354 | ); 2355 | let temp48len = fast_expansion_sum_zeroelim( 2356 | &temp16c[..temp16clen], 2357 | &temp32a[..temp32alen], 2358 | &mut temp48, 2359 | ); 2360 | finlength = 2361 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2362 | core::mem::swap(&mut finnow, &mut finother); 2363 | } 2364 | if adxtail != 0.0 || adytail != 0.0 { 2365 | let mut bctlen = 1; 2366 | let mut bcttlen = 1; 2367 | let mut bct: [f64; 8] = [0.; 8]; 2368 | let mut bctt: [f64; 4] = [0.; 4]; 2369 | if bdxtail != 0.0 || bdytail != 0.0 || cdxtail != 0.0 || cdytail != 0.0 { 2370 | let [ti0, ti1] = two_product(bdxtail, cdy); 2371 | let [tj0, tj1] = two_product(bdx, cdytail); 2372 | let u = two_two_sum(ti1, ti0, tj1, tj0); 2373 | let negate = -bdy; 2374 | let [ti0, ti1] = two_product(cdxtail, negate); 2375 | let negate = -bdytail; 2376 | let [tj0, tj1] = two_product(cdx, negate); 2377 | let v = two_two_sum(ti1, ti0, tj1, tj0); 2378 | bctlen = fast_expansion_sum_zeroelim(&u, &v, &mut bct); 2379 | let [ti0, ti1] = two_product(bdxtail, cdytail); 2380 | let [tj0, tj1] = two_product(cdxtail, bdytail); 2381 | bctt = two_two_diff(ti1, ti0, tj1, tj0); 2382 | bcttlen = 4; 2383 | } 2384 | if adxtail != 0.0 { 2385 | let temp16alen = scale_expansion_zeroelim(&axtbc[..axtbclen], adxtail, &mut temp16a); 2386 | let axtbctlen = scale_expansion_zeroelim(&bct[..bctlen], adxtail, &mut axtbct); 2387 | let temp32alen = 2388 | scale_expansion_zeroelim(&axtbct[..axtbctlen], 2.0 * adx, &mut temp32a); 2389 | let temp48len = fast_expansion_sum_zeroelim( 2390 | &temp16a[..temp16alen], 2391 | &temp32a[..temp32alen], 2392 | &mut temp48, 2393 | ); 2394 | finlength = 2395 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2396 | core::mem::swap(&mut finnow, &mut finother); 2397 | if bdytail != 0.0 { 2398 | let temp8len = scale_expansion_zeroelim(&cc, adxtail, &mut temp8); 2399 | let temp16alen = 2400 | scale_expansion_zeroelim(&temp8[..temp8len], bdytail, &mut temp16a); 2401 | finlength = fast_expansion_sum_zeroelim( 2402 | &finnow[..finlength], 2403 | &temp16a[..temp16alen], 2404 | finother, 2405 | ); 2406 | core::mem::swap(&mut finnow, &mut finother); 2407 | } 2408 | if cdytail != 0.0 { 2409 | let temp8len = scale_expansion_zeroelim(&bb, -adxtail, &mut temp8); 2410 | let temp16alen = 2411 | scale_expansion_zeroelim(&temp8[..temp8len], cdytail, &mut temp16a); 2412 | finlength = fast_expansion_sum_zeroelim( 2413 | &finnow[..finlength], 2414 | &temp16a[..temp16alen], 2415 | finother, 2416 | ); 2417 | core::mem::swap(&mut finnow, &mut finother); 2418 | } 2419 | let temp32alen = scale_expansion_zeroelim(&axtbct[..axtbctlen], adxtail, &mut temp32a); 2420 | let axtbcttlen = scale_expansion_zeroelim(&bctt[..bcttlen], adxtail, &mut axtbctt); 2421 | let temp16alen = 2422 | scale_expansion_zeroelim(&axtbctt[..axtbcttlen], 2.0 * adx, &mut temp16a); 2423 | let temp16blen = 2424 | scale_expansion_zeroelim(&axtbctt[..axtbcttlen], adxtail, &mut temp16b); 2425 | let temp32blen = fast_expansion_sum_zeroelim( 2426 | &temp16a[..temp16alen], 2427 | &temp16b[..temp16blen], 2428 | &mut temp32b, 2429 | ); 2430 | let temp64len = fast_expansion_sum_zeroelim( 2431 | &temp32a[..temp32alen], 2432 | &temp32b[..temp32blen], 2433 | &mut temp64, 2434 | ); 2435 | finlength = 2436 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp64[..temp64len], finother); 2437 | core::mem::swap(&mut finnow, &mut finother); 2438 | } 2439 | if adytail != 0.0 { 2440 | let temp16alen = scale_expansion_zeroelim(&aytbc[..aytbclen], adytail, &mut temp16a); 2441 | let aytbctlen = scale_expansion_zeroelim(&bct[..bctlen], adytail, &mut aytbct); 2442 | let temp32alen = 2443 | scale_expansion_zeroelim(&aytbct[..aytbctlen], 2.0 * ady, &mut temp32a); 2444 | let temp48len = fast_expansion_sum_zeroelim( 2445 | &temp16a[..temp16alen], 2446 | &temp32a[..temp32alen], 2447 | &mut temp48, 2448 | ); 2449 | finlength = 2450 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2451 | core::mem::swap(&mut finnow, &mut finother); 2452 | let temp32alen = scale_expansion_zeroelim(&aytbct[..aytbctlen], adytail, &mut temp32a); 2453 | let aytbcttlen = scale_expansion_zeroelim(&bctt[..bcttlen], adytail, &mut aytbctt); 2454 | let temp16alen = 2455 | scale_expansion_zeroelim(&aytbctt[..aytbcttlen], 2.0 * ady, &mut temp16a); 2456 | let temp16blen = 2457 | scale_expansion_zeroelim(&aytbctt[..aytbcttlen], adytail, &mut temp16b); 2458 | let temp32blen = fast_expansion_sum_zeroelim( 2459 | &temp16a[..temp16alen], 2460 | &temp16b[..temp16blen], 2461 | &mut temp32b, 2462 | ); 2463 | let temp64len = fast_expansion_sum_zeroelim( 2464 | &temp32a[..temp32alen], 2465 | &temp32b[..temp32blen], 2466 | &mut temp64, 2467 | ); 2468 | finlength = 2469 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp64[..temp64len], finother); 2470 | core::mem::swap(&mut finnow, &mut finother); 2471 | } 2472 | } 2473 | if bdxtail != 0.0 || bdytail != 0.0 { 2474 | let mut catlen = 1; 2475 | let mut cattlen = 1; 2476 | let mut cat: [f64; 8] = [0.; 8]; 2477 | let mut catt: [f64; 4] = [0.; 4]; 2478 | if cdxtail != 0.0 || cdytail != 0.0 || adxtail != 0.0 || adytail != 0.0 { 2479 | let [ti0, ti1] = two_product(cdxtail, ady); 2480 | let [tj0, tj1] = two_product(cdx, adytail); 2481 | let u = two_two_sum(ti1, ti0, tj1, tj0); 2482 | let negate = -cdy; 2483 | let [ti0, ti1] = two_product(adxtail, negate); 2484 | let negate = -cdytail; 2485 | let [tj0, tj1] = two_product(adx, negate); 2486 | let v = two_two_sum(ti1, ti0, tj1, tj0); 2487 | catlen = fast_expansion_sum_zeroelim(&u, &v, &mut cat); 2488 | let [ti0, ti1] = two_product(cdxtail, adytail); 2489 | let [tj0, tj1] = two_product(adxtail, cdytail); 2490 | catt = two_two_diff(ti1, ti0, tj1, tj0); 2491 | cattlen = 4; 2492 | } 2493 | if bdxtail != 0.0 { 2494 | let temp16alen = scale_expansion_zeroelim(&bxtca[..bxtcalen], bdxtail, &mut temp16a); 2495 | let bxtcatlen = scale_expansion_zeroelim(&cat[..catlen], bdxtail, &mut bxtcat); 2496 | let temp32alen = 2497 | scale_expansion_zeroelim(&bxtcat[..bxtcatlen], 2.0 * bdx, &mut temp32a); 2498 | let temp48len = fast_expansion_sum_zeroelim( 2499 | &temp16a[..temp16alen], 2500 | &temp32a[..temp32alen], 2501 | &mut temp48, 2502 | ); 2503 | finlength = 2504 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2505 | core::mem::swap(&mut finnow, &mut finother); 2506 | if cdytail != 0.0 { 2507 | let temp8len = scale_expansion_zeroelim(&aa, bdxtail, &mut temp8); 2508 | let temp16alen = 2509 | scale_expansion_zeroelim(&temp8[..temp8len], cdytail, &mut temp16a); 2510 | finlength = fast_expansion_sum_zeroelim( 2511 | &finnow[..finlength], 2512 | &temp16a[..temp16alen], 2513 | finother, 2514 | ); 2515 | core::mem::swap(&mut finnow, &mut finother); 2516 | } 2517 | if adytail != 0.0 { 2518 | let temp8len = scale_expansion_zeroelim(&cc, -bdxtail, &mut temp8); 2519 | let temp16alen = 2520 | scale_expansion_zeroelim(&temp8[..temp8len], adytail, &mut temp16a); 2521 | finlength = fast_expansion_sum_zeroelim( 2522 | &finnow[..finlength], 2523 | &temp16a[..temp16alen], 2524 | finother, 2525 | ); 2526 | core::mem::swap(&mut finnow, &mut finother); 2527 | } 2528 | let temp32alen = scale_expansion_zeroelim(&bxtcat[..bxtcatlen], bdxtail, &mut temp32a); 2529 | let bxtcattlen = scale_expansion_zeroelim(&catt[..cattlen], bdxtail, &mut bxtcatt); 2530 | let temp16alen = 2531 | scale_expansion_zeroelim(&bxtcatt[..bxtcattlen], 2.0 * bdx, &mut temp16a); 2532 | let temp16blen = 2533 | scale_expansion_zeroelim(&bxtcatt[..bxtcattlen], bdxtail, &mut temp16b); 2534 | let temp32blen = fast_expansion_sum_zeroelim( 2535 | &temp16a[..temp16alen], 2536 | &temp16b[..temp16blen], 2537 | &mut temp32b, 2538 | ); 2539 | let temp64len = fast_expansion_sum_zeroelim( 2540 | &temp32a[..temp32alen], 2541 | &temp32b[..temp32blen], 2542 | &mut temp64, 2543 | ); 2544 | finlength = 2545 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp64[..temp64len], finother); 2546 | core::mem::swap(&mut finnow, &mut finother); 2547 | } 2548 | if bdytail != 0.0 { 2549 | let temp16alen = scale_expansion_zeroelim(&bytca[..bytcalen], bdytail, &mut temp16a); 2550 | let bytcatlen = scale_expansion_zeroelim(&cat[..catlen], bdytail, &mut bytcat); 2551 | let temp32alen = 2552 | scale_expansion_zeroelim(&bytcat[..bytcatlen], 2.0 * bdy, &mut temp32a); 2553 | let temp48len = fast_expansion_sum_zeroelim( 2554 | &temp16a[..temp16alen], 2555 | &temp32a[..temp32alen], 2556 | &mut temp48, 2557 | ); 2558 | finlength = 2559 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2560 | core::mem::swap(&mut finnow, &mut finother); 2561 | let temp32alen = scale_expansion_zeroelim(&bytcat[..bytcatlen], bdytail, &mut temp32a); 2562 | let bytcattlen = scale_expansion_zeroelim(&catt[..cattlen], bdytail, &mut bytcatt); 2563 | let temp16alen = 2564 | scale_expansion_zeroelim(&bytcatt[..bytcattlen], 2.0 * bdy, &mut temp16a); 2565 | let temp16blen = 2566 | scale_expansion_zeroelim(&bytcatt[..bytcattlen], bdytail, &mut temp16b); 2567 | let temp32blen = fast_expansion_sum_zeroelim( 2568 | &temp16a[..temp16alen], 2569 | &temp16b[..temp16blen], 2570 | &mut temp32b, 2571 | ); 2572 | let temp64len = fast_expansion_sum_zeroelim( 2573 | &temp32a[..temp32alen], 2574 | &temp32b[..temp32blen], 2575 | &mut temp64, 2576 | ); 2577 | finlength = 2578 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp64[..temp64len], finother); 2579 | core::mem::swap(&mut finnow, &mut finother); 2580 | } 2581 | } 2582 | if cdxtail != 0.0 || cdytail != 0.0 { 2583 | let mut abtlen = 1; 2584 | let mut abttlen = 1; 2585 | let mut abt: [f64; 8] = [0.; 8]; 2586 | let mut abtt: [f64; 4] = [0.; 4]; 2587 | if adxtail != 0.0 || adytail != 0.0 || bdxtail != 0.0 || bdytail != 0.0 { 2588 | let [ti0, ti1] = two_product(adxtail, bdy); 2589 | let [tj0, tj1] = two_product(adx, bdytail); 2590 | let u = two_two_sum(ti1, ti0, tj1, tj0); 2591 | let negate = -ady; 2592 | let [ti0, ti1] = two_product(bdxtail, negate); 2593 | let negate = -adytail; 2594 | let [tj0, tj1] = two_product(bdx, negate); 2595 | let v = two_two_sum(ti1, ti0, tj1, tj0); 2596 | abtlen = fast_expansion_sum_zeroelim(&u, &v, &mut abt); 2597 | let [ti0, ti1] = two_product(adxtail, bdytail); 2598 | let [tj0, tj1] = two_product(bdxtail, adytail); 2599 | abtt = two_two_diff(ti1, ti0, tj1, tj0); 2600 | abttlen = 4; 2601 | } 2602 | if cdxtail != 0.0 { 2603 | let temp16alen = scale_expansion_zeroelim(&cxtab[..cxtablen], cdxtail, &mut temp16a); 2604 | let cxtabtlen = scale_expansion_zeroelim(&abt[..abtlen], cdxtail, &mut cxtabt); 2605 | let temp32alen = 2606 | scale_expansion_zeroelim(&cxtabt[..cxtabtlen], 2.0 * cdx, &mut temp32a); 2607 | let temp48len = fast_expansion_sum_zeroelim( 2608 | &temp16a[..temp16alen], 2609 | &temp32a[..temp32alen], 2610 | &mut temp48, 2611 | ); 2612 | finlength = 2613 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2614 | core::mem::swap(&mut finnow, &mut finother); 2615 | if adytail != 0.0 { 2616 | let temp8len = scale_expansion_zeroelim(&bb, cdxtail, &mut temp8); 2617 | let temp16alen = 2618 | scale_expansion_zeroelim(&temp8[..temp8len], adytail, &mut temp16a); 2619 | finlength = fast_expansion_sum_zeroelim( 2620 | &finnow[..finlength], 2621 | &temp16a[..temp16alen], 2622 | finother, 2623 | ); 2624 | core::mem::swap(&mut finnow, &mut finother); 2625 | } 2626 | if bdytail != 0.0 { 2627 | let temp8len = scale_expansion_zeroelim(&aa, -cdxtail, &mut temp8); 2628 | let temp16alen = 2629 | scale_expansion_zeroelim(&temp8[..temp8len], bdytail, &mut temp16a); 2630 | finlength = fast_expansion_sum_zeroelim( 2631 | &finnow[..finlength], 2632 | &temp16a[..temp16alen], 2633 | finother, 2634 | ); 2635 | core::mem::swap(&mut finnow, &mut finother); 2636 | } 2637 | let temp32alen = scale_expansion_zeroelim(&cxtabt[..cxtabtlen], cdxtail, &mut temp32a); 2638 | let cxtabttlen = scale_expansion_zeroelim(&abtt[..abttlen], cdxtail, &mut cxtabtt); 2639 | let temp16alen = 2640 | scale_expansion_zeroelim(&cxtabtt[..cxtabttlen], 2.0 * cdx, &mut temp16a); 2641 | let temp16blen = 2642 | scale_expansion_zeroelim(&cxtabtt[..cxtabttlen], cdxtail, &mut temp16b); 2643 | let temp32blen = fast_expansion_sum_zeroelim( 2644 | &temp16a[..temp16alen], 2645 | &temp16b[..temp16blen], 2646 | &mut temp32b, 2647 | ); 2648 | let temp64len = fast_expansion_sum_zeroelim( 2649 | &temp32a[..temp32alen], 2650 | &temp32b[..temp32blen], 2651 | &mut temp64, 2652 | ); 2653 | finlength = 2654 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp64[..temp64len], finother); 2655 | core::mem::swap(&mut finnow, &mut finother); 2656 | } 2657 | if cdytail != 0.0 { 2658 | let temp16alen = scale_expansion_zeroelim(&cytab[..cytablen], cdytail, &mut temp16a); 2659 | let cytabtlen = scale_expansion_zeroelim(&abt[..abtlen], cdytail, &mut cytabt); 2660 | let temp32alen = 2661 | scale_expansion_zeroelim(&cytabt[..cytabtlen], 2.0 * cdy, &mut temp32a); 2662 | let temp48len = fast_expansion_sum_zeroelim( 2663 | &temp16a[..temp16alen], 2664 | &temp32a[..temp32alen], 2665 | &mut temp48, 2666 | ); 2667 | finlength = 2668 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp48[..temp48len], finother); 2669 | core::mem::swap(&mut finnow, &mut finother); 2670 | let temp32alen = scale_expansion_zeroelim(&cytabt[..cytabtlen], cdytail, &mut temp32a); 2671 | let cytabttlen = scale_expansion_zeroelim(&abtt[..abttlen], cdytail, &mut cytabtt); 2672 | let temp16alen = 2673 | scale_expansion_zeroelim(&cytabtt[..cytabttlen], 2.0 * cdy, &mut temp16a); 2674 | let temp16blen = 2675 | scale_expansion_zeroelim(&cytabtt[..cytabttlen], cdytail, &mut temp16b); 2676 | let temp32blen = fast_expansion_sum_zeroelim( 2677 | &temp16a[..temp16alen], 2678 | &temp16b[..temp16blen], 2679 | &mut temp32b, 2680 | ); 2681 | let temp64len = fast_expansion_sum_zeroelim( 2682 | &temp32a[..temp32alen], 2683 | &temp32b[..temp32blen], 2684 | &mut temp64, 2685 | ); 2686 | finlength = 2687 | fast_expansion_sum_zeroelim(&finnow[..finlength], &temp64[..temp64len], finother); 2688 | core::mem::swap(&mut finnow, &mut finother); 2689 | } 2690 | } 2691 | finnow[finlength - 1] 2692 | } 2693 | 2694 | /** 2695 | * Adaptive exact 2D incircle test. Robust. 2696 | * 2697 | * Return a positive value if the point `pd` lies inside the 2698 | * circle passing through `pa`, `pb`, and `pc`; a negative value if 2699 | * it lies outside; and zero if the four points are cocircular. 2700 | * The points `pa`, `pb`, and `pc` must be in counterclockwise 2701 | * order, or the sign of the result will be reversed. 2702 | * 2703 | * The result returned is the determinant of a matrix. 2704 | * This determinant is computed adaptively, in the sense that exact 2705 | * arithmetic is used only to the degree it is needed to ensure that the 2706 | * returned value has the correct sign. Hence, `incircle()` is usually quite 2707 | * fast, but will run more slowly when the input points are cocircular or 2708 | * nearly so. 2709 | */ 2710 | #[inline] 2711 | pub fn incircle(pa: [f64; 2], pb: [f64; 2], pc: [f64; 2], pd: [f64; 2]) -> f64 { 2712 | let adx = pa[0] - pd[0]; 2713 | let bdx = pb[0] - pd[0]; 2714 | let cdx = pc[0] - pd[0]; 2715 | let ady = pa[1] - pd[1]; 2716 | let bdy = pb[1] - pd[1]; 2717 | let cdy = pc[1] - pd[1]; 2718 | let bdxcdy = bdx * cdy; 2719 | let cdxbdy = cdx * bdy; 2720 | let alift = adx * adx + ady * ady; 2721 | let cdxady = cdx * ady; 2722 | let adxcdy = adx * cdy; 2723 | let blift = bdx * bdx + bdy * bdy; 2724 | let adxbdy = adx * bdy; 2725 | let bdxady = bdx * ady; 2726 | let clift = cdx * cdx + cdy * cdy; 2727 | let det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady); 2728 | let permanent = (abs(bdxcdy) + abs(cdxbdy)) * alift 2729 | + (abs(cdxady) + abs(adxcdy)) * blift 2730 | + (abs(adxbdy) + abs(bdxady)) * clift; 2731 | let errbound = PARAMS.iccerrbound_a * permanent; 2732 | if det > errbound || -det > errbound { 2733 | return det; 2734 | } 2735 | incircleadapt(pa, pb, pc, pd, permanent) 2736 | } 2737 | 2738 | /* ****************************************************************************/ 2739 | /* */ 2740 | /* insphere_fast() Approximate 3D insphere test. Nonrobust. */ 2741 | /* insphere_exact() Exact 3D insphere test. Robust. */ 2742 | /* insphere_slow() Another exact 3D insphere test. Robust. */ 2743 | /* insphere() Adaptive exact 3D insphere test. Robust. */ 2744 | /* */ 2745 | /* Return a positive value if the point pe lies inside the */ 2746 | /* sphere passing through pa, pb, pc, and pd; a negative value */ 2747 | /* if it lies outside; and zero if the five points are */ 2748 | /* cospherical. The points pa, pb, pc, and pd must be ordered */ 2749 | /* so that they have a positive orientation (as defined by */ 2750 | /* orient3d()), or the sign of the result will be reversed. */ 2751 | /* */ 2752 | /* Only the first and last routine should be used; the middle two are for */ 2753 | /* timings. */ 2754 | /* */ 2755 | /* The last three use exact arithmetic to ensure a correct answer. The */ 2756 | /* result returned is the determinant of a matrix. In insphere() only, */ 2757 | /* this determinant is computed adaptively, in the sense that exact */ 2758 | /* arithmetic is used only to the degree it is needed to ensure that the */ 2759 | /* returned value has the correct sign. Hence, insphere() is usually quite */ 2760 | /* fast, but will run more slowly when the input points are cospherical or */ 2761 | /* nearly so. */ 2762 | /* */ 2763 | /* ****************************************************************************/ 2764 | 2765 | /// Approximate 3D insphere test. Non-robust version of [`insphere`]. 2766 | #[inline] 2767 | pub fn insphere_fast(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3], pe: [f64; 3]) -> f64 { 2768 | let aex = pa[0] - pe[0]; 2769 | let bex = pb[0] - pe[0]; 2770 | let cex = pc[0] - pe[0]; 2771 | let dex = pd[0] - pe[0]; 2772 | let aey = pa[1] - pe[1]; 2773 | let bey = pb[1] - pe[1]; 2774 | let cey = pc[1] - pe[1]; 2775 | let dey = pd[1] - pe[1]; 2776 | let aez = pa[2] - pe[2]; 2777 | let bez = pb[2] - pe[2]; 2778 | let cez = pc[2] - pe[2]; 2779 | let dez = pd[2] - pe[2]; 2780 | let ab = aex * bey - bex * aey; 2781 | let bc = bex * cey - cex * bey; 2782 | let cd = cex * dey - dex * cey; 2783 | let da = dex * aey - aex * dey; 2784 | let ac = aex * cey - cex * aey; 2785 | let bd = bex * dey - dex * bey; 2786 | let abc = aez * bc - bez * ac + cez * ab; 2787 | let bcd = bez * cd - cez * bd + dez * bc; 2788 | let cda = cez * da + dez * ac + aez * cd; 2789 | let dab = dez * ab + aez * bd + bez * da; 2790 | let alift = aex * aex + aey * aey + aez * aez; 2791 | let blift = bex * bex + bey * bey + bez * bez; 2792 | let clift = cex * cex + cey * cey + cez * cez; 2793 | let dlift = dex * dex + dey * dey + dez * dez; 2794 | dlift * abc - clift * dab + (blift * cda - alift * bcd) 2795 | } 2796 | 2797 | #[inline] 2798 | pub fn insphere_exact(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3], pe: [f64; 3]) -> f64 { 2799 | let mut temp8a = [0.; 8]; 2800 | let mut temp8b = [0.; 8]; 2801 | let mut temp16 = [0.; 16]; 2802 | let mut abc = [0.; 24]; 2803 | let mut bcd = [0.; 24]; 2804 | let mut cde = [0.; 24]; 2805 | let mut dea = [0.; 24]; 2806 | let mut eab = [0.; 24]; 2807 | let mut abd = [0.; 24]; 2808 | let mut bce = [0.; 24]; 2809 | let mut cda = [0.; 24]; 2810 | let mut deb = [0.; 24]; 2811 | let mut eac = [0.; 24]; 2812 | let mut temp48a = [0.; 48]; 2813 | let mut temp48b = [0.; 48]; 2814 | let mut abcd = [0.; 96]; 2815 | let mut bcde = [0.; 96]; 2816 | let mut cdea = [0.; 96]; 2817 | let mut deab = [0.; 96]; 2818 | let mut eabc = [0.; 96]; 2819 | let mut temp192 = [0.; 192]; 2820 | let mut det384x = [0.; 384]; 2821 | let mut det384y = [0.; 384]; 2822 | let mut det384z = [0.; 384]; 2823 | let mut detxy = [0.; 768]; 2824 | let mut adet = [0.; 1152]; 2825 | let mut bdet = [0.; 1152]; 2826 | let mut cdet = [0.; 1152]; 2827 | let mut ddet = [0.; 1152]; 2828 | let mut edet = [0.; 1152]; 2829 | let mut abdet = [0.; 2304]; 2830 | let mut cddet = [0.; 2304]; 2831 | let mut cdedet = [0.; 3456]; 2832 | let [axby0, axby1] = two_product(pa[0], pb[1]); 2833 | let [bxay0, bxay1] = two_product(pb[0], pa[1]); 2834 | let ab = two_two_diff(axby1, axby0, bxay1, bxay0); 2835 | let [bxcy0, bxcy1] = two_product(pb[0], pc[1]); 2836 | let [cxby0, cxby1] = two_product(pc[0], pb[1]); 2837 | let bc = two_two_diff(bxcy1, bxcy0, cxby1, cxby0); 2838 | let [cxdy0, cxdy1] = two_product(pc[0], pd[1]); 2839 | let [dxcy0, dxcy1] = two_product(pd[0], pc[1]); 2840 | let cd = two_two_diff(cxdy1, cxdy0, dxcy1, dxcy0); 2841 | let [dxey0, dxey1] = two_product(pd[0], pe[1]); 2842 | let [exdy0, exdy1] = two_product(pe[0], pd[1]); 2843 | let de = two_two_diff(dxey1, dxey0, exdy1, exdy0); 2844 | let [exay0, exay1] = two_product(pe[0], pa[1]); 2845 | let [axey0, axey1] = two_product(pa[0], pe[1]); 2846 | let ea = two_two_diff(exay1, exay0, axey1, axey0); 2847 | let [axcy0, axcy1] = two_product(pa[0], pc[1]); 2848 | let [cxay0, cxay1] = two_product(pc[0], pa[1]); 2849 | let ac = two_two_diff(axcy1, axcy0, cxay1, cxay0); 2850 | let [bxdy0, bxdy1] = two_product(pb[0], pd[1]); 2851 | let [dxby0, dxby1] = two_product(pd[0], pb[1]); 2852 | let bd = two_two_diff(bxdy1, bxdy0, dxby1, dxby0); 2853 | let [cxey0, cxey1] = two_product(pc[0], pe[1]); 2854 | let [excy0, excy1] = two_product(pe[0], pc[1]); 2855 | let ce = two_two_diff(cxey1, cxey0, excy1, excy0); 2856 | let [dxay0, dxay1] = two_product(pd[0], pa[1]); 2857 | let [axdy0, axdy1] = two_product(pa[0], pd[1]); 2858 | let da = two_two_diff(dxay1, dxay0, axdy1, axdy0); 2859 | let [exby0, exby1] = two_product(pe[0], pb[1]); 2860 | let [bxey0, bxey1] = two_product(pb[0], pe[1]); 2861 | let eb = two_two_diff(exby1, exby0, bxey1, bxey0); 2862 | let temp8alen = scale_expansion_zeroelim(&bc, pa[2], &mut temp8a); 2863 | let temp8blen = scale_expansion_zeroelim(&ac, -pb[2], &mut temp8b); 2864 | let temp16len = 2865 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2866 | let temp8alen = scale_expansion_zeroelim(&ab, pc[2], &mut temp8a); 2867 | let abclen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut abc); 2868 | let temp8alen = scale_expansion_zeroelim(&cd, pb[2], &mut temp8a); 2869 | let temp8blen = scale_expansion_zeroelim(&bd, -pc[2], &mut temp8b); 2870 | let temp16len = 2871 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2872 | let temp8alen = scale_expansion_zeroelim(&bc, pd[2], &mut temp8a); 2873 | let bcdlen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut bcd); 2874 | let temp8alen = scale_expansion_zeroelim(&de, pc[2], &mut temp8a); 2875 | let temp8blen = scale_expansion_zeroelim(&ce, -pd[2], &mut temp8b); 2876 | let temp16len = 2877 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2878 | let temp8alen = scale_expansion_zeroelim(&cd, pe[2], &mut temp8a); 2879 | let cdelen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut cde); 2880 | let temp8alen = scale_expansion_zeroelim(&ea, pd[2], &mut temp8a); 2881 | let temp8blen = scale_expansion_zeroelim(&da, -pe[2], &mut temp8b); 2882 | let temp16len = 2883 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2884 | let temp8alen = scale_expansion_zeroelim(&de, pa[2], &mut temp8a); 2885 | let dealen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut dea); 2886 | let temp8alen = scale_expansion_zeroelim(&ab, pe[2], &mut temp8a); 2887 | let temp8blen = scale_expansion_zeroelim(&eb, -pa[2], &mut temp8b); 2888 | let temp16len = 2889 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2890 | let temp8alen = scale_expansion_zeroelim(&ea, pb[2], &mut temp8a); 2891 | let eablen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut eab); 2892 | let temp8alen = scale_expansion_zeroelim(&bd, pa[2], &mut temp8a); 2893 | let temp8blen = scale_expansion_zeroelim(&da, pb[2], &mut temp8b); 2894 | let temp16len = 2895 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2896 | let temp8alen = scale_expansion_zeroelim(&ab, pd[2], &mut temp8a); 2897 | let abdlen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut abd); 2898 | let temp8alen = scale_expansion_zeroelim(&ce, pb[2], &mut temp8a); 2899 | let temp8blen = scale_expansion_zeroelim(&eb, pc[2], &mut temp8b); 2900 | let temp16len = 2901 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2902 | let temp8alen = scale_expansion_zeroelim(&bc, pe[2], &mut temp8a); 2903 | let bcelen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut bce); 2904 | let temp8alen = scale_expansion_zeroelim(&da, pc[2], &mut temp8a); 2905 | let temp8blen = scale_expansion_zeroelim(&ac, pd[2], &mut temp8b); 2906 | let temp16len = 2907 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2908 | let temp8alen = scale_expansion_zeroelim(&cd, pa[2], &mut temp8a); 2909 | let cdalen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut cda); 2910 | let temp8alen = scale_expansion_zeroelim(&eb, pd[2], &mut temp8a); 2911 | let temp8blen = scale_expansion_zeroelim(&bd, pe[2], &mut temp8b); 2912 | let temp16len = 2913 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2914 | let temp8alen = scale_expansion_zeroelim(&de, pb[2], &mut temp8a); 2915 | let deblen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut deb); 2916 | let temp8alen = scale_expansion_zeroelim(&ac, pe[2], &mut temp8a); 2917 | let temp8blen = scale_expansion_zeroelim(&ce, pa[2], &mut temp8b); 2918 | let temp16len = 2919 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 2920 | let temp8alen = scale_expansion_zeroelim(&ea, pc[2], &mut temp8a); 2921 | let eaclen = fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp16[..temp16len], &mut eac); 2922 | let temp48alen = fast_expansion_sum_zeroelim(&cde[..cdelen], &bce[..bcelen], &mut temp48a); 2923 | let temp48blen = fast_expansion_sum_zeroelim(&deb[..deblen], &bcd[..bcdlen], &mut temp48b); 2924 | temp48b[..temp48blen].iter_mut().for_each(|x| *x = -*x); 2925 | let bcdelen = 2926 | fast_expansion_sum_zeroelim(&temp48a[..temp48alen], &temp48b[..temp48blen], &mut bcde); 2927 | let xlen = scale_expansion_zeroelim(&bcde[..bcdelen], pa[0], &mut temp192); 2928 | let xlen = scale_expansion_zeroelim(&temp192[..xlen], pa[0], &mut det384x); 2929 | let ylen = scale_expansion_zeroelim(&bcde[..bcdelen], pa[1], &mut temp192); 2930 | let ylen = scale_expansion_zeroelim(&temp192[..ylen], pa[1], &mut det384y); 2931 | let zlen = scale_expansion_zeroelim(&bcde[..bcdelen], pa[2], &mut temp192); 2932 | let zlen = scale_expansion_zeroelim(&temp192[..zlen], pa[2], &mut det384z); 2933 | let xylen = fast_expansion_sum_zeroelim(&det384x[..xlen], &det384y[..ylen], &mut detxy); 2934 | let alen = fast_expansion_sum_zeroelim(&detxy[..xylen], &det384z[..zlen], &mut adet); 2935 | let temp48alen = fast_expansion_sum_zeroelim(&dea[..dealen], &cda[..cdalen], &mut temp48a); 2936 | let temp48blen = fast_expansion_sum_zeroelim(&eac[..eaclen], &cde[..cdelen], &mut temp48b); 2937 | temp48b[..temp48blen].iter_mut().for_each(|x| *x = -*x); 2938 | let cdealen = 2939 | fast_expansion_sum_zeroelim(&temp48a[..temp48alen], &temp48b[..temp48blen], &mut cdea); 2940 | let xlen = scale_expansion_zeroelim(&cdea[..cdealen], pb[0], &mut temp192); 2941 | let xlen = scale_expansion_zeroelim(&temp192[..xlen], pb[0], &mut det384x); 2942 | let ylen = scale_expansion_zeroelim(&cdea[..cdealen], pb[1], &mut temp192); 2943 | let ylen = scale_expansion_zeroelim(&temp192[..ylen], pb[1], &mut det384y); 2944 | let zlen = scale_expansion_zeroelim(&cdea[..cdealen], pb[2], &mut temp192); 2945 | let zlen = scale_expansion_zeroelim(&temp192[..zlen], pb[2], &mut det384z); 2946 | let xylen = fast_expansion_sum_zeroelim(&det384x[..xlen], &det384y[..ylen], &mut detxy); 2947 | let blen = fast_expansion_sum_zeroelim(&detxy[..xylen], &det384z[..zlen], &mut bdet); 2948 | let temp48alen = fast_expansion_sum_zeroelim(&eab[..eablen], &deb[..deblen], &mut temp48a); 2949 | let temp48blen = fast_expansion_sum_zeroelim(&abd[..abdlen], &dea[..dealen], &mut temp48b); 2950 | temp48b[..temp48blen].iter_mut().for_each(|x| *x = -*x); 2951 | let deablen = 2952 | fast_expansion_sum_zeroelim(&temp48a[..temp48alen], &temp48b[..temp48blen], &mut deab); 2953 | let xlen = scale_expansion_zeroelim(&deab[..deablen], pc[0], &mut temp192); 2954 | let xlen = scale_expansion_zeroelim(&temp192[..xlen], pc[0], &mut det384x); 2955 | let ylen = scale_expansion_zeroelim(&deab[..deablen], pc[1], &mut temp192); 2956 | let ylen = scale_expansion_zeroelim(&temp192[..ylen], pc[1], &mut det384y); 2957 | let zlen = scale_expansion_zeroelim(&deab[..deablen], pc[2], &mut temp192); 2958 | let zlen = scale_expansion_zeroelim(&temp192[..zlen], pc[2], &mut det384z); 2959 | let xylen = fast_expansion_sum_zeroelim(&det384x[..xlen], &det384y[..ylen], &mut detxy); 2960 | let clen = fast_expansion_sum_zeroelim(&detxy[..xylen], &det384z[..zlen], &mut cdet); 2961 | let temp48alen = fast_expansion_sum_zeroelim(&abc[..abclen], &eac[..eaclen], &mut temp48a); 2962 | let temp48blen = fast_expansion_sum_zeroelim(&bce[..bcelen], &eab[..eablen], &mut temp48b); 2963 | temp48b[..temp48blen].iter_mut().for_each(|x| *x = -*x); 2964 | let eabclen = 2965 | fast_expansion_sum_zeroelim(&temp48a[..temp48alen], &temp48b[..temp48blen], &mut eabc); 2966 | let xlen = scale_expansion_zeroelim(&eabc[..eabclen], pd[0], &mut temp192); 2967 | let xlen = scale_expansion_zeroelim(&temp192[..xlen], pd[0], &mut det384x); 2968 | let ylen = scale_expansion_zeroelim(&eabc[..eabclen], pd[1], &mut temp192); 2969 | let ylen = scale_expansion_zeroelim(&temp192[..ylen], pd[1], &mut det384y); 2970 | let zlen = scale_expansion_zeroelim(&eabc[..eabclen], pd[2], &mut temp192); 2971 | let zlen = scale_expansion_zeroelim(&temp192[..zlen], pd[2], &mut det384z); 2972 | let xylen = fast_expansion_sum_zeroelim(&det384x[..xlen], &det384y[..ylen], &mut detxy); 2973 | let dlen = fast_expansion_sum_zeroelim(&detxy[..xylen], &det384z[..zlen], &mut ddet); 2974 | let temp48alen = fast_expansion_sum_zeroelim(&bcd[..bcdlen], &abd[..abdlen], &mut temp48a); 2975 | let temp48blen = fast_expansion_sum_zeroelim(&cda[..cdalen], &abc[..abclen], &mut temp48b); 2976 | temp48b[..temp48blen].iter_mut().for_each(|x| *x = -*x); 2977 | let abcdlen = 2978 | fast_expansion_sum_zeroelim(&temp48a[..temp48alen], &temp48b[..temp48blen], &mut abcd); 2979 | let xlen = scale_expansion_zeroelim(&abcd[..abcdlen], pe[0], &mut temp192); 2980 | let xlen = scale_expansion_zeroelim(&temp192[..xlen], pe[0], &mut det384x); 2981 | let ylen = scale_expansion_zeroelim(&abcd[..abcdlen], pe[1], &mut temp192); 2982 | let ylen = scale_expansion_zeroelim(&temp192[..ylen], pe[1], &mut det384y); 2983 | let zlen = scale_expansion_zeroelim(&abcd[..abcdlen], pe[2], &mut temp192); 2984 | let zlen = scale_expansion_zeroelim(&temp192[..zlen], pe[2], &mut det384z); 2985 | let xylen = fast_expansion_sum_zeroelim(&det384x[..xlen], &det384y[..ylen], &mut detxy); 2986 | let elen = fast_expansion_sum_zeroelim(&detxy[..xylen], &det384z[..zlen], &mut edet); 2987 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 2988 | let cdlen = fast_expansion_sum_zeroelim(&cdet[..clen], &ddet[..dlen], &mut cddet); 2989 | let cdelen = fast_expansion_sum_zeroelim(&cddet[..cdlen], &edet[..elen], &mut cdedet); 2990 | let mut deter = [0.; 5760]; 2991 | let deterlen = fast_expansion_sum_zeroelim(&abdet[..ablen], &cdedet[..cdelen], &mut deter); 2992 | deter[deterlen - 1] 2993 | } 2994 | 2995 | #[inline] 2996 | pub fn insphere_slow(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3], pe: [f64; 3]) -> f64 { 2997 | let mut ab = [0.; 16]; 2998 | let mut bc = [0.; 16]; 2999 | let mut cd = [0.; 16]; 3000 | let mut da = [0.; 16]; 3001 | let mut ac = [0.; 16]; 3002 | let mut bd = [0.; 16]; 3003 | let mut temp32a = [0.; 32]; 3004 | let mut temp32b = [0.; 32]; 3005 | let mut temp64a = [0.; 64]; 3006 | let mut temp64b = [0.; 64]; 3007 | let mut temp64c = [0.; 64]; 3008 | let mut temp128 = [0.; 128]; 3009 | let mut temp192 = [0.; 192]; 3010 | let mut detx = [0.; 384]; 3011 | let mut detxx = [0.; 768]; 3012 | let mut detxt = [0.; 384]; 3013 | let mut detxxt = [0.; 768]; 3014 | let mut detxtxt = [0.; 768]; 3015 | let mut x1 = [0.; 1536]; 3016 | let mut x2 = [0.; 2304]; 3017 | let mut dety = [0.; 384]; 3018 | let mut detyy = [0.; 768]; 3019 | let mut detyt = [0.; 384]; 3020 | let mut detyyt = [0.; 768]; 3021 | let mut detytyt = [0.; 768]; 3022 | let mut y1 = [0.; 1536]; 3023 | let mut y2 = [0.; 2304]; 3024 | let mut detz = [0.; 384]; 3025 | let mut detzz = [0.; 768]; 3026 | let mut detzt = [0.; 384]; 3027 | let mut detzzt = [0.; 768]; 3028 | let mut detztzt = [0.; 768]; 3029 | let mut z1 = [0.; 1536]; 3030 | let mut z2 = [0.; 2304]; 3031 | let mut detxy = [0.; 4608]; 3032 | let mut adet = [0.; 6912]; 3033 | let mut bdet = [0.; 6912]; 3034 | let mut cdet = [0.; 6912]; 3035 | let mut ddet = [0.; 6912]; 3036 | let mut abdet = [0.; 13824]; 3037 | let mut cddet = [0.; 13824]; 3038 | let mut deter = [0.; 27648]; 3039 | let [aextail, aex] = two_diff(pa[0], pe[0]); 3040 | let [aeytail, aey] = two_diff(pa[1], pe[1]); 3041 | let [aeztail, aez] = two_diff(pa[2], pe[2]); 3042 | let [bextail, bex] = two_diff(pb[0], pe[0]); 3043 | let [beytail, bey] = two_diff(pb[1], pe[1]); 3044 | let [beztail, bez] = two_diff(pb[2], pe[2]); 3045 | let [cextail, cex] = two_diff(pc[0], pe[0]); 3046 | let [ceytail, cey] = two_diff(pc[1], pe[1]); 3047 | let [ceztail, cez] = two_diff(pc[2], pe[2]); 3048 | let [dextail, dex] = two_diff(pd[0], pe[0]); 3049 | let [deytail, dey] = two_diff(pd[1], pe[1]); 3050 | let [deztail, dez] = two_diff(pd[2], pe[2]); 3051 | let axby = two_two_product(aex, aextail, bey, beytail); 3052 | let negate = -aey; 3053 | let negatetail = -aeytail; 3054 | let bxay = two_two_product(bex, bextail, negate, negatetail); 3055 | let ablen = fast_expansion_sum_zeroelim(&axby, &bxay, &mut ab); 3056 | let bxcy = two_two_product(bex, bextail, cey, ceytail); 3057 | let negate = -bey; 3058 | let negatetail = -beytail; 3059 | let cxby = two_two_product(cex, cextail, negate, negatetail); 3060 | let bclen = fast_expansion_sum_zeroelim(&bxcy, &cxby, &mut bc); 3061 | let cxdy = two_two_product(cex, cextail, dey, deytail); 3062 | let negate = -cey; 3063 | let negatetail = -ceytail; 3064 | let dxcy = two_two_product(dex, dextail, negate, negatetail); 3065 | let cdlen = fast_expansion_sum_zeroelim(&cxdy, &dxcy, &mut cd); 3066 | let dxay = two_two_product(dex, dextail, aey, aeytail); 3067 | let negate = -dey; 3068 | let negatetail = -deytail; 3069 | let axdy = two_two_product(aex, aextail, negate, negatetail); 3070 | let dalen = fast_expansion_sum_zeroelim(&dxay, &axdy, &mut da); 3071 | let axcy = two_two_product(aex, aextail, cey, ceytail); 3072 | let negate = -aey; 3073 | let negatetail = -aeytail; 3074 | let cxay = two_two_product(cex, cextail, negate, negatetail); 3075 | let aclen = fast_expansion_sum_zeroelim(&axcy, &cxay, &mut ac); 3076 | let bxdy = two_two_product(bex, bextail, dey, deytail); 3077 | let negate = -bey; 3078 | let negatetail = -beytail; 3079 | let dxby = two_two_product(dex, dextail, negate, negatetail); 3080 | let bdlen = fast_expansion_sum_zeroelim(&bxdy, &dxby, &mut bd); 3081 | let temp32alen = scale_expansion_zeroelim(&cd[..cdlen], -bez, &mut temp32a); 3082 | let temp32blen = scale_expansion_zeroelim(&cd[..cdlen], -beztail, &mut temp32b); 3083 | let temp64alen = 3084 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64a); 3085 | let temp32alen = scale_expansion_zeroelim(&bd[..bdlen], cez, &mut temp32a); 3086 | let temp32blen = scale_expansion_zeroelim(&bd[..bdlen], ceztail, &mut temp32b); 3087 | let temp64blen = 3088 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64b); 3089 | let temp32alen = scale_expansion_zeroelim(&bc[..bclen], -dez, &mut temp32a); 3090 | let temp32blen = scale_expansion_zeroelim(&bc[..bclen], -deztail, &mut temp32b); 3091 | let temp64clen = 3092 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64c); 3093 | let temp128len = 3094 | fast_expansion_sum_zeroelim(&temp64a[..temp64alen], &temp64b[..temp64blen], &mut temp128); 3095 | let temp192len = 3096 | fast_expansion_sum_zeroelim(&temp64c[..temp64clen], &temp128[..temp128len], &mut temp192); 3097 | let xlen = scale_expansion_zeroelim(&temp192[..temp192len], aex, &mut detx); 3098 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], aex, &mut detxx); 3099 | let xtlen = scale_expansion_zeroelim(&temp192[..temp192len], aextail, &mut detxt); 3100 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], aex, &mut detxxt); 3101 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 3102 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], aextail, &mut detxtxt); 3103 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 3104 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 3105 | let ylen = scale_expansion_zeroelim(&temp192[..temp192len], aey, &mut dety); 3106 | let yylen = scale_expansion_zeroelim(&dety[..ylen], aey, &mut detyy); 3107 | let ytlen = scale_expansion_zeroelim(&temp192[..temp192len], aeytail, &mut detyt); 3108 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], aey, &mut detyyt); 3109 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 3110 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], aeytail, &mut detytyt); 3111 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 3112 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 3113 | let zlen = scale_expansion_zeroelim(&temp192[..temp192len], aez, &mut detz); 3114 | let zzlen = scale_expansion_zeroelim(&detz[..zlen], aez, &mut detzz); 3115 | let ztlen = scale_expansion_zeroelim(&temp192[..temp192len], aeztail, &mut detzt); 3116 | let zztlen = scale_expansion_zeroelim(&detzt[..ztlen], aez, &mut detzzt); 3117 | detzzt[..zztlen].iter_mut().for_each(|x| *x *= 2.0); 3118 | let ztztlen = scale_expansion_zeroelim(&detzt[..ztlen], aeztail, &mut detztzt); 3119 | let z1len = fast_expansion_sum_zeroelim(&detzz[..zzlen], &detzzt[..zztlen], &mut z1); 3120 | let z2len = fast_expansion_sum_zeroelim(&z1[..z1len], &detztzt[..ztztlen], &mut z2); 3121 | let xylen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut detxy); 3122 | let alen = fast_expansion_sum_zeroelim(&z2[..z2len], &detxy[..xylen], &mut adet); 3123 | let temp32alen = scale_expansion_zeroelim(&da[..dalen], cez, &mut temp32a); 3124 | let temp32blen = scale_expansion_zeroelim(&da[..dalen], ceztail, &mut temp32b); 3125 | let temp64alen = 3126 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64a); 3127 | let temp32alen = scale_expansion_zeroelim(&ac[..aclen], dez, &mut temp32a); 3128 | let temp32blen = scale_expansion_zeroelim(&ac[..aclen], deztail, &mut temp32b); 3129 | let temp64blen = 3130 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64b); 3131 | let temp32alen = scale_expansion_zeroelim(&cd[..cdlen], aez, &mut temp32a); 3132 | let temp32blen = scale_expansion_zeroelim(&cd[..cdlen], aeztail, &mut temp32b); 3133 | let temp64clen = 3134 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64c); 3135 | let temp128len = 3136 | fast_expansion_sum_zeroelim(&temp64a[..temp64alen], &temp64b[..temp64blen], &mut temp128); 3137 | let temp192len = 3138 | fast_expansion_sum_zeroelim(&temp64c[..temp64clen], &temp128[..temp128len], &mut temp192); 3139 | let xlen = scale_expansion_zeroelim(&temp192[..temp192len], bex, &mut detx); 3140 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], bex, &mut detxx); 3141 | let xtlen = scale_expansion_zeroelim(&temp192[..temp192len], bextail, &mut detxt); 3142 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], bex, &mut detxxt); 3143 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 3144 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], bextail, &mut detxtxt); 3145 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 3146 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 3147 | let ylen = scale_expansion_zeroelim(&temp192[..temp192len], bey, &mut dety); 3148 | let yylen = scale_expansion_zeroelim(&dety[..ylen], bey, &mut detyy); 3149 | let ytlen = scale_expansion_zeroelim(&temp192[..temp192len], beytail, &mut detyt); 3150 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], bey, &mut detyyt); 3151 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 3152 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], beytail, &mut detytyt); 3153 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 3154 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 3155 | let zlen = scale_expansion_zeroelim(&temp192[..temp192len], bez, &mut detz); 3156 | let zzlen = scale_expansion_zeroelim(&detz[..zlen], bez, &mut detzz); 3157 | let ztlen = scale_expansion_zeroelim(&temp192[..temp192len], beztail, &mut detzt); 3158 | let zztlen = scale_expansion_zeroelim(&detzt[..ztlen], bez, &mut detzzt); 3159 | detzzt[..zztlen].iter_mut().for_each(|x| *x *= 2.0); 3160 | let ztztlen = scale_expansion_zeroelim(&detzt[..ztlen], beztail, &mut detztzt); 3161 | let z1len = fast_expansion_sum_zeroelim(&detzz[..zzlen], &detzzt[..zztlen], &mut z1); 3162 | let z2len = fast_expansion_sum_zeroelim(&z1[..z1len], &detztzt[..ztztlen], &mut z2); 3163 | let xylen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut detxy); 3164 | let blen = fast_expansion_sum_zeroelim(&z2[..z2len], &detxy[..xylen], &mut bdet); 3165 | let temp32alen = scale_expansion_zeroelim(&ab[..ablen], -dez, &mut temp32a); 3166 | let temp32blen = scale_expansion_zeroelim(&ab[..ablen], -deztail, &mut temp32b); 3167 | let temp64alen = 3168 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64a); 3169 | let temp32alen = scale_expansion_zeroelim(&bd[..bdlen], -aez, &mut temp32a); 3170 | let temp32blen = scale_expansion_zeroelim(&bd[..bdlen], -aeztail, &mut temp32b); 3171 | let temp64blen = 3172 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64b); 3173 | let temp32alen = scale_expansion_zeroelim(&da[..dalen], -bez, &mut temp32a); 3174 | let temp32blen = scale_expansion_zeroelim(&da[..dalen], -beztail, &mut temp32b); 3175 | let temp64clen = 3176 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64c); 3177 | let temp128len = 3178 | fast_expansion_sum_zeroelim(&temp64a[..temp64alen], &temp64b[..temp64blen], &mut temp128); 3179 | let temp192len = 3180 | fast_expansion_sum_zeroelim(&temp64c[..temp64clen], &temp128[..temp128len], &mut temp192); 3181 | let xlen = scale_expansion_zeroelim(&temp192[..temp192len], cex, &mut detx); 3182 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], cex, &mut detxx); 3183 | let xtlen = scale_expansion_zeroelim(&temp192[..temp192len], cextail, &mut detxt); 3184 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], cex, &mut detxxt); 3185 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 3186 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], cextail, &mut detxtxt); 3187 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 3188 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 3189 | let ylen = scale_expansion_zeroelim(&temp192[..temp192len], cey, &mut dety); 3190 | let yylen = scale_expansion_zeroelim(&dety[..ylen], cey, &mut detyy); 3191 | let ytlen = scale_expansion_zeroelim(&temp192[..temp192len], ceytail, &mut detyt); 3192 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], cey, &mut detyyt); 3193 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 3194 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], ceytail, &mut detytyt); 3195 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 3196 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 3197 | let zlen = scale_expansion_zeroelim(&temp192[..temp192len], cez, &mut detz); 3198 | let zzlen = scale_expansion_zeroelim(&detz[..zlen], cez, &mut detzz); 3199 | let ztlen = scale_expansion_zeroelim(&temp192[..temp192len], ceztail, &mut detzt); 3200 | let zztlen = scale_expansion_zeroelim(&detzt[..ztlen], cez, &mut detzzt); 3201 | detzzt[..zztlen].iter_mut().for_each(|x| *x *= 2.0); 3202 | let ztztlen = scale_expansion_zeroelim(&detzt[..ztlen], ceztail, &mut detztzt); 3203 | let z1len = fast_expansion_sum_zeroelim(&detzz[..zzlen], &detzzt[..zztlen], &mut z1); 3204 | let z2len = fast_expansion_sum_zeroelim(&z1[..z1len], &detztzt[..ztztlen], &mut z2); 3205 | let xylen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut detxy); 3206 | let clen = fast_expansion_sum_zeroelim(&z2[..z2len], &detxy[..xylen], &mut cdet); 3207 | let temp32alen = scale_expansion_zeroelim(&bc[..bclen], aez, &mut temp32a); 3208 | let temp32blen = scale_expansion_zeroelim(&bc[..bclen], aeztail, &mut temp32b); 3209 | let temp64alen = 3210 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64a); 3211 | let temp32alen = scale_expansion_zeroelim(&ac[..aclen], -bez, &mut temp32a); 3212 | let temp32blen = scale_expansion_zeroelim(&ac[..aclen], -beztail, &mut temp32b); 3213 | let temp64blen = 3214 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64b); 3215 | let temp32alen = scale_expansion_zeroelim(&ab[..ablen], cez, &mut temp32a); 3216 | let temp32blen = scale_expansion_zeroelim(&ab[..ablen], ceztail, &mut temp32b); 3217 | let temp64clen = 3218 | fast_expansion_sum_zeroelim(&temp32a[..temp32alen], &temp32b[..temp32blen], &mut temp64c); 3219 | let temp128len = 3220 | fast_expansion_sum_zeroelim(&temp64a[..temp64alen], &temp64b[..temp64blen], &mut temp128); 3221 | let temp192len = 3222 | fast_expansion_sum_zeroelim(&temp64c[..temp64clen], &temp128[..temp128len], &mut temp192); 3223 | let xlen = scale_expansion_zeroelim(&temp192[..temp192len], dex, &mut detx); 3224 | let xxlen = scale_expansion_zeroelim(&detx[..xlen], dex, &mut detxx); 3225 | let xtlen = scale_expansion_zeroelim(&temp192[..temp192len], dextail, &mut detxt); 3226 | let xxtlen = scale_expansion_zeroelim(&detxt[..xtlen], dex, &mut detxxt); 3227 | detxxt[..xxtlen].iter_mut().for_each(|x| *x *= 2.0); 3228 | let xtxtlen = scale_expansion_zeroelim(&detxt[..xtlen], dextail, &mut detxtxt); 3229 | let x1len = fast_expansion_sum_zeroelim(&detxx[..xxlen], &detxxt[..xxtlen], &mut x1); 3230 | let x2len = fast_expansion_sum_zeroelim(&x1[..x1len], &detxtxt[..xtxtlen], &mut x2); 3231 | let ylen = scale_expansion_zeroelim(&temp192[..temp192len], dey, &mut dety); 3232 | let yylen = scale_expansion_zeroelim(&dety[..ylen], dey, &mut detyy); 3233 | let ytlen = scale_expansion_zeroelim(&temp192[..temp192len], deytail, &mut detyt); 3234 | let yytlen = scale_expansion_zeroelim(&detyt[..ytlen], dey, &mut detyyt); 3235 | detyyt[..yytlen].iter_mut().for_each(|x| *x *= 2.0); 3236 | let ytytlen = scale_expansion_zeroelim(&detyt[..ytlen], deytail, &mut detytyt); 3237 | let y1len = fast_expansion_sum_zeroelim(&detyy[..yylen], &detyyt[..yytlen], &mut y1); 3238 | let y2len = fast_expansion_sum_zeroelim(&y1[..y1len], &detytyt[..ytytlen], &mut y2); 3239 | let zlen = scale_expansion_zeroelim(&temp192[..temp192len], dez, &mut detz); 3240 | let zzlen = scale_expansion_zeroelim(&detz[..zlen], dez, &mut detzz); 3241 | let ztlen = scale_expansion_zeroelim(&temp192[..temp192len], deztail, &mut detzt); 3242 | let zztlen = scale_expansion_zeroelim(&detzt[..ztlen], dez, &mut detzzt); 3243 | detzzt[..zztlen].iter_mut().for_each(|x| *x *= 2.0); 3244 | let ztztlen = scale_expansion_zeroelim(&detzt[..ztlen], deztail, &mut detztzt); 3245 | let z1len = fast_expansion_sum_zeroelim(&detzz[..zzlen], &detzzt[..zztlen], &mut z1); 3246 | let z2len = fast_expansion_sum_zeroelim(&z1[..z1len], &detztzt[..ztztlen], &mut z2); 3247 | let xylen = fast_expansion_sum_zeroelim(&x2[..x2len], &y2[..y2len], &mut detxy); 3248 | let dlen = fast_expansion_sum_zeroelim(&z2[..z2len], &detxy[..xylen], &mut ddet); 3249 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 3250 | let cdlen = fast_expansion_sum_zeroelim(&cdet[..clen], &ddet[..dlen], &mut cddet); 3251 | let deterlen = fast_expansion_sum_zeroelim(&abdet[..ablen], &cddet[..cdlen], &mut deter); 3252 | deter[deterlen - 1] 3253 | } 3254 | 3255 | #[inline] 3256 | pub fn insphereadapt( 3257 | pa: [f64; 3], 3258 | pb: [f64; 3], 3259 | pc: [f64; 3], 3260 | pd: [f64; 3], 3261 | pe: [f64; 3], 3262 | permanent: f64, 3263 | ) -> f64 { 3264 | let mut temp8a: [f64; 8] = [0.; 8]; 3265 | let mut temp8b: [f64; 8] = [0.; 8]; 3266 | let mut temp8c: [f64; 8] = [0.; 8]; 3267 | let mut temp16: [f64; 16] = [0.; 16]; 3268 | let mut temp24: [f64; 24] = [0.; 24]; 3269 | let mut temp48: [f64; 48] = [0.; 48]; 3270 | let mut xdet: [f64; 96] = [0.; 96]; 3271 | let mut ydet: [f64; 96] = [0.; 96]; 3272 | let mut zdet: [f64; 96] = [0.; 96]; 3273 | let mut xydet: [f64; 192] = [0.; 192]; 3274 | let mut adet: [f64; 288] = [0.; 288]; 3275 | let mut bdet: [f64; 288] = [0.; 288]; 3276 | let mut cdet: [f64; 288] = [0.; 288]; 3277 | let mut ddet: [f64; 288] = [0.; 288]; 3278 | let mut abdet: [f64; 576] = [0.; 576]; 3279 | let mut cddet: [f64; 576] = [0.; 576]; 3280 | let mut fin1: [f64; 1152] = [0.; 1152]; 3281 | let aex = pa[0] - pe[0]; 3282 | let bex = pb[0] - pe[0]; 3283 | let cex = pc[0] - pe[0]; 3284 | let dex = pd[0] - pe[0]; 3285 | let aey = pa[1] - pe[1]; 3286 | let bey = pb[1] - pe[1]; 3287 | let cey = pc[1] - pe[1]; 3288 | let dey = pd[1] - pe[1]; 3289 | let aez = pa[2] - pe[2]; 3290 | let bez = pb[2] - pe[2]; 3291 | let cez = pc[2] - pe[2]; 3292 | let dez = pd[2] - pe[2]; 3293 | let [aexbey0, aexbey1] = two_product(aex, bey); 3294 | let [bexaey0, bexaey1] = two_product(bex, aey); 3295 | let ab = two_two_diff(aexbey1, aexbey0, bexaey1, bexaey0); 3296 | let [bexcey0, bexcey1] = two_product(bex, cey); 3297 | let [cexbey0, cexbey1] = two_product(cex, bey); 3298 | let bc = two_two_diff(bexcey1, bexcey0, cexbey1, cexbey0); 3299 | let [cexdey0, cexdey1] = two_product(cex, dey); 3300 | let [dexcey0, dexcey1] = two_product(dex, cey); 3301 | let cd = two_two_diff(cexdey1, cexdey0, dexcey1, dexcey0); 3302 | let [dexaey0, dexaey1] = two_product(dex, aey); 3303 | let [aexdey0, aexdey1] = two_product(aex, dey); 3304 | let da = two_two_diff(dexaey1, dexaey0, aexdey1, aexdey0); 3305 | let [aexcey0, aexcey1] = two_product(aex, cey); 3306 | let [cexaey0, cexaey1] = two_product(cex, aey); 3307 | let ac = two_two_diff(aexcey1, aexcey0, cexaey1, cexaey0); 3308 | let [bexdey0, bexdey1] = two_product(bex, dey); 3309 | let [dexbey0, dexbey1] = two_product(dex, bey); 3310 | let bd = two_two_diff(bexdey1, bexdey0, dexbey1, dexbey0); 3311 | let temp8alen = scale_expansion_zeroelim(&cd, bez, &mut temp8a); 3312 | let temp8blen = scale_expansion_zeroelim(&bd, -cez, &mut temp8b); 3313 | let temp8clen = scale_expansion_zeroelim(&bc, dez, &mut temp8c); 3314 | let temp16len = 3315 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 3316 | let temp24len = 3317 | fast_expansion_sum_zeroelim(&temp8c[..temp8clen], &temp16[..temp16len], &mut temp24); 3318 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], aex, &mut temp48); 3319 | let xlen = scale_expansion_zeroelim(&temp48[..temp48len], -aex, &mut xdet); 3320 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], aey, &mut temp48); 3321 | let ylen = scale_expansion_zeroelim(&temp48[..temp48len], -aey, &mut ydet); 3322 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], aez, &mut temp48); 3323 | let zlen = scale_expansion_zeroelim(&temp48[..temp48len], -aez, &mut zdet); 3324 | let xylen = fast_expansion_sum_zeroelim(&xdet[..xlen], &ydet[..ylen], &mut xydet); 3325 | let alen = fast_expansion_sum_zeroelim(&xydet[..xylen], &zdet[..zlen], &mut adet); 3326 | let temp8alen = scale_expansion_zeroelim(&da, cez, &mut temp8a); 3327 | let temp8blen = scale_expansion_zeroelim(&ac, dez, &mut temp8b); 3328 | let temp8clen = scale_expansion_zeroelim(&cd, aez, &mut temp8c); 3329 | let temp16len = 3330 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 3331 | let temp24len = 3332 | fast_expansion_sum_zeroelim(&temp8c[..temp8clen], &temp16[..temp16len], &mut temp24); 3333 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], bex, &mut temp48); 3334 | let xlen = scale_expansion_zeroelim(&temp48[..temp48len], bex, &mut xdet); 3335 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], bey, &mut temp48); 3336 | let ylen = scale_expansion_zeroelim(&temp48[..temp48len], bey, &mut ydet); 3337 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], bez, &mut temp48); 3338 | let zlen = scale_expansion_zeroelim(&temp48[..temp48len], bez, &mut zdet); 3339 | let xylen = fast_expansion_sum_zeroelim(&xdet[..xlen], &ydet[..ylen], &mut xydet); 3340 | let blen = fast_expansion_sum_zeroelim(&xydet[..xylen], &zdet[..zlen], &mut bdet); 3341 | let temp8alen = scale_expansion_zeroelim(&ab, dez, &mut temp8a); 3342 | let temp8blen = scale_expansion_zeroelim(&bd, aez, &mut temp8b); 3343 | let temp8clen = scale_expansion_zeroelim(&da, bez, &mut temp8c); 3344 | let temp16len = 3345 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 3346 | let temp24len = 3347 | fast_expansion_sum_zeroelim(&temp8c[..temp8clen], &temp16[..temp16len], &mut temp24); 3348 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], cex, &mut temp48); 3349 | let xlen = scale_expansion_zeroelim(&temp48[..temp48len], -cex, &mut xdet); 3350 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], cey, &mut temp48); 3351 | let ylen = scale_expansion_zeroelim(&temp48[..temp48len], -cey, &mut ydet); 3352 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], cez, &mut temp48); 3353 | let zlen = scale_expansion_zeroelim(&temp48[..temp48len], -cez, &mut zdet); 3354 | let xylen = fast_expansion_sum_zeroelim(&xdet[..xlen], &ydet[..ylen], &mut xydet); 3355 | let clen = fast_expansion_sum_zeroelim(&xydet[..xylen], &zdet[..zlen], &mut cdet); 3356 | let temp8alen = scale_expansion_zeroelim(&bc, aez, &mut temp8a); 3357 | let temp8blen = scale_expansion_zeroelim(&ac, -bez, &mut temp8b); 3358 | let temp8clen = scale_expansion_zeroelim(&ab, cez, &mut temp8c); 3359 | let temp16len = 3360 | fast_expansion_sum_zeroelim(&temp8a[..temp8alen], &temp8b[..temp8blen], &mut temp16); 3361 | let temp24len = 3362 | fast_expansion_sum_zeroelim(&temp8c[..temp8clen], &temp16[..temp16len], &mut temp24); 3363 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], dex, &mut temp48); 3364 | let xlen = scale_expansion_zeroelim(&temp48[..temp48len], dex, &mut xdet); 3365 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], dey, &mut temp48); 3366 | let ylen = scale_expansion_zeroelim(&temp48[..temp48len], dey, &mut ydet); 3367 | let temp48len = scale_expansion_zeroelim(&temp24[..temp24len], dez, &mut temp48); 3368 | let zlen = scale_expansion_zeroelim(&temp48[..temp48len], dez, &mut zdet); 3369 | let xylen = fast_expansion_sum_zeroelim(&xdet[..xlen], &ydet[..ylen], &mut xydet); 3370 | let dlen = fast_expansion_sum_zeroelim(&xydet[..xylen], &zdet[..zlen], &mut ddet); 3371 | let ablen = fast_expansion_sum_zeroelim(&adet[..alen], &bdet[..blen], &mut abdet); 3372 | let cdlen = fast_expansion_sum_zeroelim(&cdet[..clen], &ddet[..dlen], &mut cddet); 3373 | let finlength = fast_expansion_sum_zeroelim(&abdet[..ablen], &cddet[..cdlen], &mut fin1); 3374 | let mut det: f64 = fin1[..finlength].iter().sum(); 3375 | let errbound = PARAMS.isperrbound_b * permanent; 3376 | if det >= errbound || -det >= errbound { 3377 | return det; 3378 | } 3379 | let aextail = two_diff_tail(pa[0], pe[0], aex); 3380 | let aeytail = two_diff_tail(pa[1], pe[1], aey); 3381 | let aeztail = two_diff_tail(pa[2], pe[2], aez); 3382 | let bextail = two_diff_tail(pb[0], pe[0], bex); 3383 | let beytail = two_diff_tail(pb[1], pe[1], bey); 3384 | let beztail = two_diff_tail(pb[2], pe[2], bez); 3385 | let cextail = two_diff_tail(pc[0], pe[0], cex); 3386 | let ceytail = two_diff_tail(pc[1], pe[1], cey); 3387 | let ceztail = two_diff_tail(pc[2], pe[2], cez); 3388 | let dextail = two_diff_tail(pd[0], pe[0], dex); 3389 | let deytail = two_diff_tail(pd[1], pe[1], dey); 3390 | let deztail = two_diff_tail(pd[2], pe[2], dez); 3391 | if aextail == 0.0 3392 | && aeytail == 0.0 3393 | && aeztail == 0.0 3394 | && bextail == 0.0 3395 | && beytail == 0.0 3396 | && beztail == 0.0 3397 | && cextail == 0.0 3398 | && ceytail == 0.0 3399 | && ceztail == 0.0 3400 | && dextail == 0.0 3401 | && deytail == 0.0 3402 | && deztail == 0.0 3403 | { 3404 | return det; 3405 | } 3406 | let errbound = PARAMS.isperrbound_c * permanent + PARAMS.resulterrbound * abs(det); 3407 | let abeps = aex * beytail + bey * aextail - (aey * bextail + bex * aeytail); 3408 | let bceps = bex * ceytail + cey * bextail - (bey * cextail + cex * beytail); 3409 | let cdeps = cex * deytail + dey * cextail - (cey * dextail + dex * ceytail); 3410 | let daeps = dex * aeytail + aey * dextail - (dey * aextail + aex * deytail); 3411 | let aceps = aex * ceytail + cey * aextail - (aey * cextail + cex * aeytail); 3412 | let bdeps = bex * deytail + dey * bextail - (bey * dextail + dex * beytail); 3413 | det += (bex * bex + bey * bey + bez * bez) 3414 | * (cez * daeps 3415 | + dez * aceps 3416 | + aez * cdeps 3417 | + (ceztail * da[3] + deztail * ac[3] + aeztail * cd[3])) 3418 | + (dex * dex + dey * dey + dez * dez) 3419 | * (aez * bceps - bez * aceps 3420 | + cez * abeps 3421 | + (aeztail * bc[3] - beztail * ac[3] + ceztail * ab[3])) 3422 | - ((aex * aex + aey * aey + aez * aez) 3423 | * (bez * cdeps - cez * bdeps 3424 | + dez * bceps 3425 | + (beztail * cd[3] - ceztail * bd[3] + deztail * bc[3])) 3426 | + (cex * cex + cey * cey + cez * cez) 3427 | * (dez * abeps 3428 | + aez * bdeps 3429 | + bez * daeps 3430 | + (deztail * ab[3] + aeztail * bd[3] + beztail * da[3]))) 3431 | + 2.0 3432 | * ((bex * bextail + bey * beytail + bez * beztail) 3433 | * (cez * da[3] + dez * ac[3] + aez * cd[3]) 3434 | + (dex * dextail + dey * deytail + dez * deztail) 3435 | * (aez * bc[3] - bez * ac[3] + cez * ab[3]) 3436 | - ((aex * aextail + aey * aeytail + aez * aeztail) 3437 | * (bez * cd[3] - cez * bd[3] + dez * bc[3]) 3438 | + (cex * cextail + cey * ceytail + cez * ceztail) 3439 | * (dez * ab[3] + aez * bd[3] + bez * da[3]))); 3440 | if det >= errbound || -det >= errbound { 3441 | return det; 3442 | } 3443 | insphere_exact(pa, pb, pc, pd, pe) 3444 | } 3445 | 3446 | /** 3447 | * Adaptive exact 3D insphere test. Robust. 3448 | * 3449 | * Return a positive value if the point `pe` lies inside the 3450 | * sphere passing through `pa`, `pb`, `pc`, and `pd`; a negative value 3451 | * if it lies outside; and zero if the five points are 3452 | * cospherical. The points `pa`, `pb`, `pc`, and `pd` must be ordered 3453 | * so that they have a positive orientation (as defined by 3454 | * `orient3d()`), or the sign of the result will be reversed. 3455 | * 3456 | * The result returned is the determinant of a matrix. 3457 | * this determinant is computed adaptively, in the sense that exact 3458 | * arithmetic is used only to the degree it is needed to ensure that the 3459 | * returned value has the correct sign. Hence, `insphere()` is usually quite 3460 | * fast, but will run more slowly when the input points are cospherical or 3461 | * nearly so. 3462 | */ 3463 | #[inline] 3464 | pub fn insphere(pa: [f64; 3], pb: [f64; 3], pc: [f64; 3], pd: [f64; 3], pe: [f64; 3]) -> f64 { 3465 | let aex = pa[0] - pe[0]; 3466 | let bex = pb[0] - pe[0]; 3467 | let cex = pc[0] - pe[0]; 3468 | let dex = pd[0] - pe[0]; 3469 | let aey = pa[1] - pe[1]; 3470 | let bey = pb[1] - pe[1]; 3471 | let cey = pc[1] - pe[1]; 3472 | let dey = pd[1] - pe[1]; 3473 | let aez = pa[2] - pe[2]; 3474 | let bez = pb[2] - pe[2]; 3475 | let cez = pc[2] - pe[2]; 3476 | let dez = pd[2] - pe[2]; 3477 | let aexbey = aex * bey; 3478 | let bexaey = bex * aey; 3479 | let ab = aexbey - bexaey; 3480 | let bexcey = bex * cey; 3481 | let cexbey = cex * bey; 3482 | let bc = bexcey - cexbey; 3483 | let cexdey = cex * dey; 3484 | let dexcey = dex * cey; 3485 | let cd = cexdey - dexcey; 3486 | let dexaey = dex * aey; 3487 | let aexdey = aex * dey; 3488 | let da = dexaey - aexdey; 3489 | let aexcey = aex * cey; 3490 | let cexaey = cex * aey; 3491 | let ac = aexcey - cexaey; 3492 | let bexdey = bex * dey; 3493 | let dexbey = dex * bey; 3494 | let bd = bexdey - dexbey; 3495 | let abc = aez * bc - bez * ac + cez * ab; 3496 | let bcd = bez * cd - cez * bd + dez * bc; 3497 | let cda = cez * da + dez * ac + aez * cd; 3498 | let dab = dez * ab + aez * bd + bez * da; 3499 | let alift = aex * aex + aey * aey + aez * aez; 3500 | let blift = bex * bex + bey * bey + bez * bez; 3501 | let clift = cex * cex + cey * cey + cez * cez; 3502 | let dlift = dex * dex + dey * dey + dez * dez; 3503 | let det = dlift * abc - clift * dab + (blift * cda - alift * bcd); 3504 | let aezplus = abs(aez); 3505 | let bezplus = abs(bez); 3506 | let cezplus = abs(cez); 3507 | let dezplus = abs(dez); 3508 | let aexbeyplus = abs(aexbey); 3509 | let bexaeyplus = abs(bexaey); 3510 | let bexceyplus = abs(bexcey); 3511 | let cexbeyplus = abs(cexbey); 3512 | let cexdeyplus = abs(cexdey); 3513 | let dexceyplus = abs(dexcey); 3514 | let dexaeyplus = abs(dexaey); 3515 | let aexdeyplus = abs(aexdey); 3516 | let aexceyplus = abs(aexcey); 3517 | let cexaeyplus = abs(cexaey); 3518 | let bexdeyplus = abs(bexdey); 3519 | let dexbeyplus = abs(dexbey); 3520 | let permanent = ((cexdeyplus + dexceyplus) * bezplus 3521 | + (dexbeyplus + bexdeyplus) * cezplus 3522 | + (bexceyplus + cexbeyplus) * dezplus) 3523 | * alift 3524 | + ((dexaeyplus + aexdeyplus) * cezplus 3525 | + (aexceyplus + cexaeyplus) * dezplus 3526 | + (cexdeyplus + dexceyplus) * aezplus) 3527 | * blift 3528 | + ((aexbeyplus + bexaeyplus) * dezplus 3529 | + (bexdeyplus + dexbeyplus) * aezplus 3530 | + (dexaeyplus + aexdeyplus) * bezplus) 3531 | * clift 3532 | + ((bexceyplus + cexbeyplus) * aezplus 3533 | + (cexaeyplus + aexceyplus) * bezplus 3534 | + (aexbeyplus + bexaeyplus) * cezplus) 3535 | * dlift; 3536 | let errbound = PARAMS.isperrbound_a * permanent; 3537 | if det > errbound || -det > errbound { 3538 | return det; 3539 | } 3540 | insphereadapt(pa, pb, pc, pd, pe, permanent) 3541 | } 3542 | -------------------------------------------------------------------------------- /src/transpiled.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | mod c2rust; 3 | 4 | pub use self::c2rust::exactinit; 5 | 6 | /* 7 | * Below are safe wrappers for the directly transpiled predicates located in the c2rust module. 8 | * 9 | * This module is used for testing the ported rust predicates, and is not intended to be used directly. 10 | */ 11 | 12 | #[inline] 13 | pub fn orient2d(mut pa: [f64; 2], mut pb: [f64; 2], mut pc: [f64; 2]) -> f64 { 14 | unsafe { c2rust::orient2d(pa.as_mut_ptr(), pb.as_mut_ptr(), pc.as_mut_ptr()) } 15 | } 16 | #[inline] 17 | pub fn orient2dexact(mut pa: [f64; 2], mut pb: [f64; 2], mut pc: [f64; 2]) -> f64 { 18 | unsafe { c2rust::orient2dexact(pa.as_mut_ptr(), pb.as_mut_ptr(), pc.as_mut_ptr()) } 19 | } 20 | #[inline] 21 | pub fn orient2dslow(mut pa: [f64; 2], mut pb: [f64; 2], mut pc: [f64; 2]) -> f64 { 22 | unsafe { c2rust::orient2dslow(pa.as_mut_ptr(), pb.as_mut_ptr(), pc.as_mut_ptr()) } 23 | } 24 | #[inline] 25 | pub fn orient3d(mut pa: [f64; 3], mut pb: [f64; 3], mut pc: [f64; 3], mut pd: [f64; 3]) -> f64 { 26 | unsafe { 27 | c2rust::orient3d( 28 | pa.as_mut_ptr(), 29 | pb.as_mut_ptr(), 30 | pc.as_mut_ptr(), 31 | pd.as_mut_ptr(), 32 | ) 33 | } 34 | } 35 | #[inline] 36 | pub fn orient3dexact( 37 | mut pa: [f64; 3], 38 | mut pb: [f64; 3], 39 | mut pc: [f64; 3], 40 | mut pd: [f64; 3], 41 | ) -> f64 { 42 | unsafe { 43 | c2rust::orient3dexact( 44 | pa.as_mut_ptr(), 45 | pb.as_mut_ptr(), 46 | pc.as_mut_ptr(), 47 | pd.as_mut_ptr(), 48 | ) 49 | } 50 | } 51 | #[inline] 52 | pub fn orient3dslow(mut pa: [f64; 3], mut pb: [f64; 3], mut pc: [f64; 3], mut pd: [f64; 3]) -> f64 { 53 | unsafe { 54 | c2rust::orient3dslow( 55 | pa.as_mut_ptr(), 56 | pb.as_mut_ptr(), 57 | pc.as_mut_ptr(), 58 | pd.as_mut_ptr(), 59 | ) 60 | } 61 | } 62 | #[inline] 63 | pub fn incircle(mut pa: [f64; 2], mut pb: [f64; 2], mut pc: [f64; 2], mut pd: [f64; 2]) -> f64 { 64 | unsafe { 65 | c2rust::incircle( 66 | pa.as_mut_ptr(), 67 | pb.as_mut_ptr(), 68 | pc.as_mut_ptr(), 69 | pd.as_mut_ptr(), 70 | ) 71 | } 72 | } 73 | #[inline] 74 | pub fn incircleexact( 75 | mut pa: [f64; 2], 76 | mut pb: [f64; 2], 77 | mut pc: [f64; 2], 78 | mut pd: [f64; 2], 79 | ) -> f64 { 80 | unsafe { 81 | c2rust::incircleexact( 82 | pa.as_mut_ptr(), 83 | pb.as_mut_ptr(), 84 | pc.as_mut_ptr(), 85 | pd.as_mut_ptr(), 86 | ) 87 | } 88 | } 89 | #[inline] 90 | pub fn incircleslow(mut pa: [f64; 2], mut pb: [f64; 2], mut pc: [f64; 2], mut pd: [f64; 2]) -> f64 { 91 | unsafe { 92 | c2rust::incircleslow( 93 | pa.as_mut_ptr(), 94 | pb.as_mut_ptr(), 95 | pc.as_mut_ptr(), 96 | pd.as_mut_ptr(), 97 | ) 98 | } 99 | } 100 | #[inline] 101 | pub fn insphere( 102 | mut pa: [f64; 3], 103 | mut pb: [f64; 3], 104 | mut pc: [f64; 3], 105 | mut pd: [f64; 3], 106 | mut pe: [f64; 3], 107 | ) -> f64 { 108 | unsafe { 109 | c2rust::insphere( 110 | pa.as_mut_ptr(), 111 | pb.as_mut_ptr(), 112 | pc.as_mut_ptr(), 113 | pd.as_mut_ptr(), 114 | pe.as_mut_ptr(), 115 | ) 116 | } 117 | } 118 | #[inline] 119 | pub fn insphereexact( 120 | mut pa: [f64; 3], 121 | mut pb: [f64; 3], 122 | mut pc: [f64; 3], 123 | mut pd: [f64; 3], 124 | mut pe: [f64; 3], 125 | ) -> f64 { 126 | unsafe { 127 | c2rust::insphereexact( 128 | pa.as_mut_ptr(), 129 | pb.as_mut_ptr(), 130 | pc.as_mut_ptr(), 131 | pd.as_mut_ptr(), 132 | pe.as_mut_ptr(), 133 | ) 134 | } 135 | } 136 | #[inline] 137 | pub fn insphereslow( 138 | mut pa: [f64; 3], 139 | mut pb: [f64; 3], 140 | mut pc: [f64; 3], 141 | mut pd: [f64; 3], 142 | mut pe: [f64; 3], 143 | ) -> f64 { 144 | unsafe { 145 | c2rust::insphereslow( 146 | pa.as_mut_ptr(), 147 | pb.as_mut_ptr(), 148 | pc.as_mut_ptr(), 149 | pd.as_mut_ptr(), 150 | pe.as_mut_ptr(), 151 | ) 152 | } 153 | } 154 | --------------------------------------------------------------------------------