Skip to content

CCMath 0.3.0 Release Candidate#149

Open
Rinzii wants to merge 6 commits into
review-base/v0.2.0from
release/0.3.x
Open

CCMath 0.3.0 Release Candidate#149
Rinzii wants to merge 6 commits into
review-base/v0.2.0from
release/0.3.x

Conversation

@Rinzii

@Rinzii Rinzii commented Jun 14, 2026

Copy link
Copy Markdown
Owner

CCMath 0.3.0 Release Candidate

This is the review PR for v0.3.0. The goal is to catch any remaining blockers before the
release is cut.

It puts the entire v0.2.0 to v0.3.0 change set in one diff. It is review-only and will not be
merged. The base branch review-base/v0.2.0 is a frozen snapshot of the v0.2.0 tag, so the
diff is exactly what landed since the last release. The content itself already lives on main
and on release/0.3.x.

How this review works: comments here are the review record. Fixes land as normal PRs into
main, after which release/0.3.x is fast-forwarded. Record your approval as a review here.
When review wraps up, the PR is closed and review-base/v0.2.0 is deleted. Treat it as a diff
viewer and discussion thread.

The user-facing summary is in the release notes. What follows is for reviewers: what changed,
where the risk is, what is validated, and what would block the release.

Heads up on size: 891 files, about +59.6k / -9.8k. Most of it is build, tooling, test, and
doc work rather than runtime math kernels. The part that can produce silently wrong numbers
though is small and it is listed below first.

What counts as blocking

Reasons to hold the release. Mark these clearly so they stand out from nits:

  • A numeric result that violates the documented contract or a release claim, in any rounding
    mode, on a supported path.
  • Wrong dispatch or format selection (for example a powl call routed to the wrong kernel).
  • A public API contract problem in the new ext or fmanip functions (signature, NaN and
    infinity behavior, constexpr-ness).
  • A claim in the release notes the code does not actually support.
  • A portability break on a supported compiler or standard mode (C++17 through C++26).

Most other items can be handled as nits or follow-ups unless they change the release risk.
Items under Known limitations are out of scope by design, not blockers, unless you can show
one breaks a supported path.

Where to focus review

These are the surfaces where a mistake means wrong math, so they earn the closest reading.
Validation has been run on most of them (see Validation status), but that lowers the
uncertainty rather than removing the need for attention.

Trigonometry (double sin, cos, tan)

  • sincos_payne_hanek.hpp plus the
    sin, cos, and tan kernels.
  • What to check: the Payne-Hanek large-argument reduction, the binary64 constant values, the
    quadrant selection, sign-of-zero handling, and the inverse-trig edge cases (asin, acos,
    atan, atan2). The earlier failure mode was large arguments falling outside the
    reduction, so large-input behavior is the thing to primarily probe.

Power (double pow, long double powl)

  • The double-double constant pairs in the pow path. The headline bug class fixed this
    release was hi and lo halves stored swapped, which is harmless under round-to-nearest but
    wrong in directed modes, so check each DD constant against its intended value and ordering.
  • The new 80-bit powl kernel:
    powl_ld80_kernel.hpp
    and its generated
    powl_ld80_tables.hpp.
    It compiles only where long double is the 80-bit x87 extended format, so the double and
    IEEE binary128 long double platforms do not exercise it. This is preview quality (see
    Known limitations).
  • SIMD pow paths: pow_simd_impl.hpp and powf_simd_impl.hpp in the same directory. These
    run only under runtime SIMD (not deterministic mode), so the check is that they agree with
    the scalar path on the same inputs.

Configuration and dispatch

  • long_double_format.hpp and
    powl_policy.hpp decide which long double
    path is taken. A wrong detection sends every powl call down the wrong kernel, so the
    format-detection logic is worth careful eyes.
  • Deterministic mode (CCMATH_ENABLE_DETERMINISTIC): the claim is bit-identical float and
    double results across supported hardware. Worth confirming it forces the generic kernels, disables
    runtime SIMD, does not leak into a libm or compiler builtin on any path, and that constexpr
    and runtime agree. long double is not part of the deterministic claim.

New public API

  • The 15 new ccm::ext helpers under ext/ and the standard nextup
    and nextdown under fmanip/. Check signatures, NaN and
    infinity behavior, constexpr-ness, and that they build clean under -Wconversion. The ext
    helpers are opt-in behind CCMATH_ENABLE_EXTENSIONS, so also check the namespace placement
    and that they stay out of a default build.

Low-level support

  • support/fp/: cast.hpp, except_value_utils.hpp,
    fma.hpp. The changes here are small, but used very widely so mistake can easily propagate.

Lower-risk areas (skim)

  • ccm::pp SIMD layer under runtime/pp/: a
    standalone C++17 port of the C++26 std::simd interface. Not yet wired into dispatch, so it
    cannot change results this release. Review it on its own merits if you have the appetite,
    otherwise it can wait.
  • Tests under tests/: new conformance, rigorous, and proof harnesses. The useful
    question here is coverage gaps against the kernels above.
  • Fuzzing under fuzzing/: libFuzzer targets per family.
  • Tooling: asmlab under tools/asmlab/, the showcase comparisons, and the
    benchmarks. Build and dev infrastructure, not part of library runtime behavior.
  • Build systems: meson.build, premake5.lua, the CMake options, and the vendored-consumer
    integration test.
  • CI under .github/workflows/: the C++23 and C++26 matrix and the
    per-PR clang-format gate.
  • Docs and proofs: a partial POW_PROOF.tex (the full binary64 proof is still open) and the
    Sollya and Gappa scripts under docs/approximating_functions.

Validation status

What has been validated, and how. This lowers the uncertainty on these areas, it does not put
them out of bounds for review:

  • pow: CORE-MATH all-mode validation campaigns over the covered inputs, all four rounding
    modes. The campaign records live under tests/rigorous/ (see oracle_logs/ for the
    per-campaign summaries).
  • sin, cos, tan: full-range validation campaigns, large arguments included. This is
    representative coverage across the range, not an exhaustive sweep of every binary64 value.
  • fma: all-mode exact software fallback, with native runtime coverage validated on AArch64.
  • Differential fuzzing across the basic, compare, exponential, float-manipulation, misc,
    nearest, power, and trig families.
  • Builds under -Werror with aggressive warnings (-Wconversion and friends) across the CI
    matrix on Linux, macOS, and Windows.

Open validation work (not expected to be finished in this RC):

  • The full binary64 pow proof. The writeup in the tree is partial.
  • powf reduced-domain validation.
  • Independent validation of the 80-bit powl kernel.
  • Wider x86-64 fma validation.

Known limitations and intended scope

These are disclosed in the release notes and are intentionally out of scope for v0.3.0. Call
one out if you think it should block the release, otherwise treat it as known debt:

  • The 80-bit powl kernel is preview quality. Its generic fuzz lane is intentionally guarded
    off in power_fuzz.cpp until the kernel is finalized.
  • Deterministic mode is experimental.
  • Hyperbolic and special functions are still empty headers.

Building and validating locally

It is a header-only library, so consuming it is just an include. To exercise the validation
that matters for review:

cmake -S . -B build -DCCMATH_BUILD_RIGOROUS_TESTS=ON \
  -DCCMATH_ENABLE_WARNINGS_AS_ERRORS=ON -DCCMATH_ENABLE_AGGRESSIVE_WARNINGS=ON
cmake --build build --config Release
ctest --test-dir build --output-on-failure -C Release

On multi-config generators like MSVC the --config and -C Release flags matter, and they
are harmless elsewhere. Add -DCCMATH_ENABLE_MPFR_TESTS=ON and
-DCCMATH_ENABLE_COREMATH_TESTS=ON for the oracle-backed campaigns (these need MPFR and
CORE-MATH available, and the rigorous runs can take a while). Fuzzers build under Clang with
-DCCMATH_BUILD_FUZZING=ON. Run tools/ensure_format.sh for the format gate. The README
validation section and tools/asmlab/README.md cover the deeper tooling.

Where review is most valuable

Highest value first: numeric correctness and edge cases in the kernels above, then the public
API shape of the new ext and fmanip functions, then test coverage gaps against those
kernels. Style and tooling nits are welcome but lowest priority for an RC this size.

@Rinzii Rinzii self-assigned this Jun 14, 2026
@Rinzii Rinzii added the RC Release Candidate label Jun 14, 2026
@Rinzii Rinzii added this to the Road to v1.0.0 milestone Jun 14, 2026
@Rinzii Rinzii requested a review from nekoflare June 14, 2026 00:55
Comment thread include/ccmath/ext/abs_diff.hpp Outdated
@Rinzii Rinzii requested a review from Eczbek June 14, 2026 01:18
Comment thread include/ccmath/ext/ceil_div.hpp
Comment thread include/ccmath/ext/chgsign.hpp
Comment thread include/ccmath/ext/mix.hpp
{
return static_cast<T>(1) / x;
}
{ return static_cast<T>(1) / x; }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Casting of literals is inconsistent between files, sometimes T(123) and sometimes static_cast<T>(123)

{
const T length = src_end - src_start;

if (length == T(0)) { return dst_start; }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does it make sense to compare floating-point values with ==? Perhaps approximately() can be used instead. This might also apply to other files.

template <typename T>
inline constexpr bool has_constexpr_abs =
#ifdef CCMATH_HAS_CONSTEXPR_BUILTIN_ABS
std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, long double> || std::is_same_v<T, long long> || (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Did you mean to std::remove_cv_t<T>? Checking std::is_same_v<T, long long> seems redundant because of the std::is_integral_v<T> check. Checking whether T is signed or unsigned seems redundant too, and is this intended to allow bool?

Also, it might be beneficial to make a helper:

template <typename First, typename... Rest>
inline constexpr bool is_same_any = (... || std::is_same_v<First, Rest>);

// ...

template <typename T>
inline constexpr bool has_constexpr_abs = is_same_any<std::remove_cv_t<T>, float, double, long double> // ...

@@ -65,9 +65,7 @@ namespace ccm

template <typename T, typename U, typename TC = std::common_type_t<T, U>>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is TC intended to be customizable by the user?

Comment thread include/ccmath/internal/math/runtime/pp/assume_aligned.hpp
template <typename... Fs>
struct flags_align_request<simd_flags<Fs...>>
: std::integral_constant<std::size_t,
((std::size_t{ 0 } + ... + overalign_value<Fs>::value) != 0)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

More inconsistent casting of literals, now with curly braces

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I could enforce a convention with an AST matcher but I'm not sure if it's worth the effort or not. Thoughts?

Comment thread include/ccmath/internal/support/fp/cast.hpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RC Release Candidate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants