Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

rgeometry/apfp

Open more actions menu

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

Packages

 
 
 

Contributors

Morty Proxy This is a proxified and sanitized view of the page, visit original site.