Skip to content

BUG: Define vnl_math::sqrteps as exactly-representable 0x1p-26#1051

Closed
hjmjohnson wants to merge 1 commit into
vxl:masterfrom
hjmjohnson:fix-vnl-sqrteps-exact-2pow26
Closed

BUG: Define vnl_math::sqrteps as exactly-representable 0x1p-26#1051
hjmjohnson wants to merge 1 commit into
vxl:masterfrom
hjmjohnson:fix-vnl-sqrteps-exact-2pow26

Conversation

@hjmjohnson

Copy link
Copy Markdown
Contributor

Define vnl_math::sqrteps as the exactly-representable 0x1p-26 instead of the 1-ULP-high decimal literal 1.490116119384766e-08.

Why 0x1p-26 is the correct value

sqrteps is sqrt(eps) where eps = std::numeric_limits<double>::epsilon() = 2^-52. Therefore sqrteps = sqrt(2^-52) = 2^-26, a power of two and exactly representable as a double (decimal 1.490116119384765625e-8).

The previous literal 1.490116119384766e-08 is 3.75e-24 above that exact value, exceeding the half-ULP threshold (~1.65e-24), so it rounds to 2^-26 + 2^-78 — one ULP high. 0x1p-26 is the simplest unambiguous spelling and equals what IEEE-754 correctly-rounded sqrt(eps) returns at runtime (and what C++26 constexpr std::sqrt(eps) will yield).

vgl already relies on the exact value: core/vgl/vgl_triangle_3d.cxx computes sqrteps = std::sqrt(std::numeric_limits<double>::epsilon()) at runtime, which is exactly 0x1p-26.

Impact / testing
  • No vnl test asserts the literal value — core/vnl/tests/test_math.cxx only takes &vnl_math::sqrteps (symbol-existence check).
  • Existing consumers (pdf1d, clsfy) use sqrteps as a convergence/comparison tolerance, where a 1-ULP change is negligible.
  • Verified locally: the hex literal compiles under C++17 and 0x1p-26 == std::sqrt(std::numeric_limits<double>::epsilon()).

sqrteps is meant to be sqrt(eps) where eps is std::numeric_limits<
double>::epsilon() = 2^-52. The exact value sqrt(2^-52) = 2^-26 is a
power of two and therefore exactly representable as a double; in
decimal it is 1.490116119384765625e-8.

The previous literal 1.490116119384766e-08 is 3.75e-24 above that
exact value, exceeding the half-ULP threshold (~1.65e-24), so it
rounds to 2^-26 + 2^-78 -- one ULP high. The hex float 0x1p-26 is the
simplest unambiguous spelling of the intended value and matches what
IEEE-754 correctly-rounded sqrt(eps) returns at runtime (and what
C++26 constexpr std::sqrt(eps) will yield).

vgl already relies on the exact value: core/vgl/vgl_triangle_3d.cxx
computes sqrteps = std::sqrt(numeric_limits<double>::epsilon()) at
runtime, which is exactly 0x1p-26.

Reported via greptile review on InsightSoftwareConsortium/ITK PR #6427.
@hjmjohnson hjmjohnson marked this pull request as ready for review June 10, 2026 13:01
@hjmjohnson hjmjohnson requested review from TimCootes and Copilot June 10, 2026 13:06

Copilot AI left a comment

Copy link
Copy Markdown

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 corrects vnl_math::sqrteps to be the exactly representable value of sqrt(std::numeric_limits<double>::epsilon()) by replacing a slightly-too-large decimal literal with the precise hexadecimal floating-point literal 0x1p-26.

Changes:

  • Replace vnl_math::sqrteps’s decimal literal with 0x1p-26 to represent 2^-26 exactly.
  • Add an explanatory comment documenting why 0x1p-26 is the correct value for sqrt(eps).

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

@hjmjohnson

Copy link
Copy Markdown
Contributor Author

Moving ITK efforts for VXL to https://github.com/InsightSoftwareConsortium/vxl/tree/for/itk-vxl-master. This is primarily so that the ITK development team can focus on the ITK-needed features of vxl and remove the rest.

@hjmjohnson hjmjohnson closed this Jun 11, 2026
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.

2 participants