QCAD Bugtracker

  • Status Assigned
  • Percent Complete
    0%
  • Task Type Refactoring
  • Category QCAD (main)
  • Assigned To
    andrew
  • Operating System All
  • Severity Low
  • Priority Very Low
  • Reported Version 3.32.9
  • Due in Version Undecided
  • Due Date Undecided
  • Votes
  • Private
Attached to Project: QCAD Bugtracker
Opened by CVH - 15.08.2026
Last edited by CVH - 15.08.2026

FS#2741 - Comparing values with the squared tolerance (1e-18)

Andrew,

Nicely summarized by an AI:
Comparing two floating-point values within a tolerance is NOT
the same as comparing their squared values within the squared tolerance.
Squaring changes the scale of values and the distance between them.
This breaks the linear logic used in standard tolerance checks, especially for values near zero or larger values.

Why These Methods Are Not Equal:
- Different scaling near zero:
If a = 0.1 and b = 0.2, their absolute difference is 0.1.
Their squared values are 0.01 and 0.04, with a difference of 0.03 (three times smaller).
- Different scaling for large values:
If a = 1000.1 and b = 1000.2, their difference is 0.1,
but their squared values differ by about 200 (2000 times larger).
- Tolerance distortion:
A linear tolerance epsilon allows a fixed window [a-epsilon < b < a+epsilon]. Squaring maps this to a non-linear, asymmetric range that grows much faster for larger base values.

When It Fails:
- Small values (<±1):
The squared difference becomes much smaller than the linear difference.
A tolerance that passes linear values might fail squared values.
- Larger values (>±1):
The squared difference becomes much larger than the linear difference.
A tolerance that passes linear values will likely fail squared values.
- Negative values: Squaring loses the sign.
If (a = -1.001) and (b = 1.001), they are far apart linearly,
but their squared values are nearly identical (1.002 vs 1.002).



Recently implemented at various places in QCAD.
For example to compare a distance in XY with a value within tolerance avoiding the
sqrt() for the vector magnitude.
Where the distance d = sqrt(dX²+dY²+dZ²) is compared with a positive value v within a small tolerance (e.g. RS.PointTolerance = 1e-9)
Including dZ because there is no 2D variant for RVector::getSquaredMagnitude().
Or for example where the squared distance is calulated in direct as dSqr = dX²+dY².

Typically worked out as fabs(d - v) < 1e-9 (analog of RMath.fuzzyCompare).
What results in fabs(sqrt(dX²+dY²) - v) < 1e-9.

And then falsely replaced by fabs(dX²+dY² - v²) < 1e-9*1e-9
Or comparing a difference to within 1e-18.
In the case of larger numbers (>1):
Subtracting 2 much larger but near equal values with no more than 17 significant digits.

Also algebraically incorrect !
Squaring both sides of (|d - v| < tol) to exploit instead of d results in: ((d - v)² < tol²)
And this expands to: (d² - 2dv + v² < tol²) where the root d is still present.

(fabs(d - v) < tol) is already a reduction of a window comparison: (d > v-tol && d < v+tol)
At best, avoiding the subtraction of a small value in floating point: (d+tol > v && d < v+tol)
We then also avoid digit cancellation when subtracting larger values in fabs(d - v).
But squaring this also leads to ((d+tol)² > v²) or (d²+2*d*tol+tol² > v²) for the first test.



With the initial window comparison:
Squaring (d > v-tol && d < v+tol) results in: (d² > (v-tol)² && d² < (v+tol)²)
In wich we can replace and the intended value v ≈ sqrt(d²) to compare with:
(dSqr=dX²+dY² > (v-tol)² && dSqr=dX²+dY² < (v+tol)²)

This may fail when (d == v).
And always when tol is too small to be added or subtracted in floating-point.
When comparing (squared) values within a small tolerance we must thus include equality:

if (dSqr >= (v-tol)*(v-tol) && dSqr <= (v+tol)*(v+tol)) {...}

Programmatically more complex …
… and perhaps no longer a faster method than taking the root.
The second test is skipped when the first is true.

It certainly avoids the absurd comparison with 1e-18.
Because that is mostly true for real near equal distances.

Regards,
CVH

Loading...

Available keyboard shortcuts

Tasklist

Task Details

Task Editing