Skip to content

Add snap_fp fixed-precision floating point type#10

Open
Copilot wants to merge 9 commits intomasterfrom
copilot/add-snap-floating-point-type
Open

Add snap_fp fixed-precision floating point type#10
Copilot wants to merge 9 commits intomasterfrom
copilot/add-snap-floating-point-type

Conversation

Copy link

Copilot AI commented Jan 31, 2026

Implements a drop-in replacement for float/double that snaps values to a fixed-precision grid, addressing floating point precision issues in sensitive algorithms.

Implementation

  • src/YgorSnap.h - Header-only template class snap_fp<T, ScaleFactor>

    • Internal representation: int64_t scaled by template parameter
    • 128-bit arithmetic (__int128) for mul/div to prevent overflow, with integer-based fallback algorithms when 128-bit types are unavailable
    • Overflow detection for addition/subtraction operations (throws std::overflow_error)
    • Full operator overloads: arithmetic, comparison, unary, compound assignment
    • Math functions: abs, sqrt, floor, ceil, round, fmod, min, max, pow, trig, exp, log
    • Additional scientific math functions: log1p, log2, expm1, exp2, cbrt, hypot, sinh, cosh, tanh, asinh, acosh, atanh, erf, erfc, tgamma, lgamma, trunc, copysign, fma, remainder, lerp, clamp, isfinite, isnan, isinf, signbit
    • Stream I/O, explicit conversion, utility functions
    • Type aliases: snap_double_micro (1e-6), snap_double_nano (1e-9), etc.
  • tests/Test_Snap_01.cc - Unit tests for all functionality

Usage

#include "YgorSnap.h"

// Values snap to 1e-6 precision grid
snap_fp<double, 1000000> a(1.234567);  // internal: 1234567
snap_fp<double, 1000000> b(0.000001);  // internal: 1

auto c = a + b;  // Pure integer addition internally
c.to_fp();       // Returns 1.234568

// Repeated operations are deterministic (no FP drift)
snap_fp<double, 1000000> sum;
for (int i = 0; i < 10; ++i) sum += snap_fp<double, 1000000>(0.1);
// sum.to_fp() == 1.0 exactly

Design Notes

  • Different scale factors are incompatible at compile time (static_assert)
  • Operations with raw floating point values supported via operator overloads
  • Throws std::domain_error for division by zero, sqrt(negative), log(non-positive)
  • Throws std::overflow_error for arithmetic operations that would overflow the int64_t range

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits January 31, 2026 07:55
Co-authored-by: hdclark <934858+hdclark@users.noreply.github.com>
Co-authored-by: hdclark <934858+hdclark@users.noreply.github.com>
Copilot AI changed the title [WIP] Add snap replacement class for floating point types Add snap_fp fixed-precision floating point type Jan 31, 2026
Copilot AI requested a review from hdclark January 31, 2026 07:59
@hdclark hdclark marked this pull request as ready for review January 31, 2026 07:59
Copilot AI review requested due to automatic review settings January 31, 2026 07:59
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a fixed-precision floating-point type snap_fp<T, ScaleFactor> to address floating-point precision issues in sensitive algorithms. The implementation stores values as scaled integers internally, providing deterministic rounding and avoiding accumulation of floating-point errors.

Changes:

  • Adds src/YgorSnap.h with header-only template class providing full arithmetic, comparison, and mathematical function support
  • Adds comprehensive unit tests in tests/Test_Snap_01.cc covering construction, operators, edge cases, and error handling
  • Updates tests/compile.sh to build the new test

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
src/YgorSnap.h Header-only implementation of snap_fp template class with integer-backed fixed-precision arithmetic
tests/Test_Snap_01.cc Comprehensive unit tests validating all snap_fp functionality including edge cases and error conditions
tests/compile.sh Added compilation command for new snap_fp test

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +197 to +202
#else
// Fallback for systems without 128-bit integers.
// Use floating point for intermediate calculation.
T result = to_fp() * other.to_fp();
return snap_fp(result);
#endif
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On systems without 128-bit integer support (when SIZEOF_INT128 is not defined), the multiplication and division operators fall back to using floating-point arithmetic. This defeats the primary purpose of snap_fp, which is to avoid floating-point precision issues by using integer arithmetic. Consider documenting this limitation prominently in the class documentation, or implementing alternative integer-based algorithms that work without 128-bit types (though these would be more complex and potentially slower).

Copilot uses AI. Check for mistakes.
Copy link
Owner

@hdclark hdclark Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implement alternative integer-based algorithms that work without 128-bit types, but only as fallbacks when 128-bit integers are not available.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented integer-based fallback algorithms (multiply_scaled and divide_scaled) that use long double for intermediate values when 128-bit integers are not available. The fallback now properly handles large values with overflow detection while avoiding the floating-point precision issues of the original T-based fallback. Commit: 0051884

src/YgorSnap.h Outdated
Comment on lines +182 to +184
constexpr snap_fp operator+(const snap_fp &other) const {
return snap_fp(raw_tag{}, m_value + other.m_value);
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition and subtraction operators do not check for overflow. When adding or subtracting large values, the result could overflow the int64_t range, leading to undefined behavior. Consider adding overflow detection or documenting this limitation, especially since the valid range of representable values is approximately [-INT64_MAX/ScaleFactor, INT64_MAX/ScaleFactor].

Copilot uses AI. Check for mistakes.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add overflow detection.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added checked_add and checked_sub helper functions that detect overflow before performing the operation and throw std::overflow_error when the result would overflow the int64_t range. The compound assignment operators (+=, -=) also now use these checked functions. Commit: 0051884

hdclark and others added 5 commits February 26, 2026 22:09
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@hdclark
Copy link
Owner

hdclark commented Feb 27, 2026

@copilot apply changes based on the comments in this thread

Also provide additional mathematical overloads appropriate for typical scientific use.

…functions

Co-authored-by: hdclark <934858+hdclark@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 27, 2026

@copilot apply changes based on the comments in this thread

Also provide additional mathematical overloads appropriate for ty...

Applied all review changes and added additional mathematical overloads for scientific use:

Precision-preserving variants: log1p, log2, expm1, exp2
Root functions: cbrt, hypot
Hyperbolic functions: sinh, cosh, tanh, asinh, acosh, atanh
Special functions: erf, erfc, tgamma, lgamma
Utility functions: trunc, copysign, fma, remainder, lerp, clamp
Classification functions: isfinite, isnan, isinf, signbit

Commit: 0051884

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants