MSVC's Debug code generator does not dead-code-eliminate after an `if constexpr`
chain whose branches all return, so the fallthrough `return` after the chain is
flagged C4702 (unreachable) on instantiations where one of the branches is
selected. Release builds optimize the dead path out and never complain.
Restructure two places so the fallback lives inside an explicit `else` /
returning helper instead of a fallthrough:
* `enforce_bounds()` (quantity_point.h): wrap the `return q;` fallback in
`else { return q; }` after the existing `if constexpr` chain.
* `compare_quantities()` (quantity.h): hoist the floating-point / already-widest
fallback into a local `fallback_cmp` lambda invoked from both arms of the
`if constexpr` chain. Keeps the existing float-equal suppression.
For `CHECK_THROWS_AS` in constrained_test.cpp, Catch2's macro expands into a
try/catch whose catch arm becomes unreachable when the body calls a `[[noreturn]]`
function; suppress C4702 around that one TEST_CASE since the macro is not ours
to restructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Fix#580: use fixed-point arithmetic for integer unit conversions
Introduce a fixed-point implementation for unit conversions involving
integer representations, avoiding loss of significant digits that
previously occurred when the conversion factor was not a whole number.
New files:
- src/core/include/mp-units/bits/fixed_point.h: double_width_int<T> and
fixed_point<T,n> types for exact rational scaling of integer values.
Uses __int128 when available (__SIZEOF_INT128__) for 64-bit integers.
- src/core/include/mp-units/framework/scaling.h: public scaling_traits<>
customization point and scale<To>(M, value) free function. Provides
built-in specializations for floating-point and integer-like types.
- test/static/fixed_point_test.cpp: static assertions for the new types.
- test/runtime/fixed_point_test.cpp: runtime arithmetic edge-case tests.
Modified:
- sudo_cast.h: replace hand-rolled conversion_value_traits / sudo_cast_value
machinery with a single scale<To::rep>(c_mag, ...) call.
- representation_concepts.h: add MagnitudeScalable concept; replace
ComplexScalar with HasComplexOperations (which is its definition).
- customization_points.h: add unspecified_rep tag and declare the primary
scaling_traits<> template.
- framework.h / CMakeLists.txt: wire in the new headers.
- hacks.h: add MP_UNITS_DIAGNOSTIC_IGNORE_PEDANTIC and
MP_UNITS_DIAGNOSTIC_IGNORE_SIGN_CONVERSION macros.
- example/measurement.cpp: add scaling_traits specializations for
measurement<T> to demonstrate the customization point.
- test/static/{international,usc}_test.cpp: disable two tests that are
blocked on issue #614.
Co-authored-by: Tobias Hanhart <burnpanck@users.noreply.github.com>
* Fix value_Type typo in floating_point_scaling_factor_type specialization
The partial specialization for types with a nested value_type used
'value_Type' (capital T) instead of 'value_type', making the entire
specialization dead code as the requires-clause could never be satisfied.
Also fix 'mantiassa' -> 'mantissa' in the adjacent comment.
* Fix docstring typos in scaling_traits documentation
- 'quantitiy' -> 'quantity'
- 'dictatet' -> 'dictated'
- 'convetrible' -> 'convertible'
- 'implemenation' -> 'implementation'
- 'availabe' -> 'available'
* Fix conflict resolution error: keep ComplexScalar name from master
When resolving the merge conflict in representation_concepts.h, the
PR's renamed version of the concept ('HasComplexOperations') was used
instead of master's established name ('ComplexScalar'). The two concepts
are semantically equivalent — burnpanck simply renamed it in his branch.
Revert to the canonical 'ComplexScalar' name while retaining the new
'MagnitudeScalable' concept which was the actual addition from the PR.
* Fix measurement.cpp: remove duplicate class definition from merge
The PR branched from a version where measurement<T> was defined inline
in measurement.cpp. Master later moved the class to example/include/
measurement.h and changed measurement.cpp to #include that header.
The squash merge therefore introduced a duplicate definition: the class
from the header and the PR's inline class were both visible, causing
an 'ambiguous reference' error. Remove the now-redundant inline class;
the scaling_traits specializations added by the PR work correctly with
the class from measurement.h.
* style: pre-commit
* docs: chapters anchors improved in the "custom representation" chapter
* docs: value conversions chapter improved
* refactor: scaling support refactored
* fix: clang-16 crash fixed
* docs: `measurement` example documentation updated to match changes
* fix: use exact wide-integer arithmetic for rational unit conversions on all platforms
On ARM / Apple Silicon, long double == double (64-bit mantissa). The old
fixed_point<T>(long double) initialiser lost ~12 bits of precision for 64-bit
integer types when representing the scaling ratio, producing an error of ~49
units for the 10/9 (degree → gradian) conversion with a 10^18 input value.
Fix by splitting the integer-path else-branch into two cases:
• Pure rational M (is_integral(M * (denominator(M) / numerator(M))) == true):
use (value * numerator) / denominator via double_width_int_for_t<> arithmetic.
This is exact on every platform regardless of long double width.
• Irrational M (involves π etc.): keep the long double fixed_point approximation.
These conversions are inherently approximate; small values still produce correct
truncated results on all platforms.
Update the test comment to reflect the new exact-arithmetic path.
Fixes CI failures on clang-18/ARM and apple-clang-16.
* fix: replace floating-point TeX-point test with exact integer equivalent
72.27 is not exactly representable as double (it rounds to 72.2699...96).
Multiplying by the conversion factor 100/7227 via long double gives a result
≥ 1.0 on x86 (80-bit long double, 64-bit mantissa) only by chance, but
0.99999...978 on ARM / Apple Silicon where long double == double (52-bit).
The correct mathematical statement is: 7227 tex_point = 100 inch (exact
rational relationship). Use that integer form instead of the inexact 72.27
double literal so the test is correct and platform-independent.
---------
Co-authored-by: Tobias Hanhart <burnpanck@users.noreply.github.com>
Replace runtime unit access (q.unit) with compile-time type extraction
(get_unit(R)) in the inverse function implementation. This prevents the
function from becoming an immediate function when consteval unit operators
are used, allowing inverse to work with runtime variables.
Key changes:
- math.h: Use get_unit(R) instead of q.unit in both code paths
- test: Add comprehensive runtime inverse tests
This surgical fix preserves maximum compile-time optimization while
enabling DSP applications that need runtime inverse calculations.
Fixes compilation error with Clang:
"call to immediate function 'inverse' is not a constant expression"
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>