Skip to content

rgeometry/apfp

Repository files navigation

apfp - Adaptive Precision Floating-Point

Robust geometric predicates using adaptive precision arithmetic. The library provides exact sign computation for arithmetic expressions, automatically escalating precision only when needed.

Features

  • Robust geometric predicates: orient2d, incircle, cmp_dist that handle near-degenerate cases correctly
  • General-purpose sign computation: The apfp_signum! macro computes exact signs for arbitrary arithmetic expressions
  • Adaptive staging: Fast f64 evaluation with error bounds, falling back to double-double or exact arithmetic only when necessary
  • Allocation-free: All operations use fixed stack buffers computed at compile time

Quick Start

[dependencies]
apfp = "0.1"

Using Pre-built Predicates

use apfp::geometry::f64::{Coord, orient2d, cmp_dist, Orientation};
use std::cmp::Ordering;

let a = Coord::new(0.0, 0.0);
let b = Coord::new(1.0, 0.0);
let c = Coord::new(0.5, 1e-16);

// Orientation test: is c left of, right of, or on line ab?
match orient2d(&a, &b, &c) {
    Orientation::CounterClockwise => println!("Counter-clockwise"),
    Orientation::Clockwise => println!("Clockwise"),
    Orientation::CoLinear => println!("Collinear"),
}

// Distance comparison: is p closer to origin than q?
let origin = Coord::new(0.0, 0.0);
let p = Coord::new(1.0, 0.0);
let q = Coord::new(0.0, 1.0);
match cmp_dist(&origin, &p, &q) {
    Ordering::Less => println!("p is closer"),
    Ordering::Greater => println!("q is closer"),
    Ordering::Equal => println!("equidistant"),
}

Building Custom Expressions

Use apfp_signum! to compute the exact sign of any arithmetic expression:

use apfp::{apfp_signum, square};

// Compute sign of a determinant
let a = 1.0_f64;
let b = 2.0_f64;
let c = 3.0_f64;
let d = 4.0_f64;
let sign = apfp_signum!(a * d - b * c);
assert_eq!(sign, -1); // 1*4 - 2*3 = -2 < 0

// Use square() for squared terms (more efficient than x * x)
let x = 3.0_f64;
let y = 4.0_f64;
let z = 5.0_f64;
let sign = apfp_signum!(square(x) + square(y) - square(z));
assert_eq!(sign, 0); // 9 + 16 - 25 = 0

The macro supports +, -, *, and square() operations on f64 values.

How It Works

The library implements Shewchuk's adaptive precision arithmetic:

  1. Fast path: Evaluate in f64 and compute an error bound. If the result magnitude exceeds the bound, return immediately.
  2. Double-double path: Re-evaluate using double-double arithmetic (~106 bits). Check against tighter bounds.
  3. Exact path: Compute the exact result using floating-point expansions.

Most calls complete in the fast path. The adaptive approach provides both correctness and performance.

Performance

On random inputs, orient2d performs within 1.1x of the geometry-predicates crate (which uses the same underlying algorithm). The macro-based approach allows the compiler to inline and optimize the entire computation.

Requirements

  • IEEE 754 binary floating-point with round-to-nearest-even
  • Rust 2024 edition

License

This project is released under The Unlicense.

About

Adaptive Precision Float-Point arithmetic

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published