// The MIT License (MIT) // // Copyright (c) 2018 Mateusz Pusz // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include #include #include #include #ifdef MP_UNITS_IMPORT_STD import std; #else #include #include #endif using namespace mp_units; namespace { // min_width_uint_t selects the narrowest standard unsigned type that holds N bits static_assert(std::is_same_v, std::uint8_t>); static_assert(std::is_same_v, std::uint8_t>); static_assert(std::is_same_v, std::uint8_t>); static_assert(std::is_same_v, std::uint16_t>); static_assert(std::is_same_v, std::uint32_t>); static_assert(std::is_same_v, std::uint32_t>); static_assert(std::is_same_v, std::uint64_t>); // scale(M{}, value) — integer-to-integer path (exact arithmetic, no floating point) // integral factor: exact integer multiply static_assert(scale(mag<1000>, 5) == 5000); static_assert(scale(mag<60>, 2l) == 120l); // integral inverse: exact integer divide static_assert(scale(mag_ratio<1, 1000>, 5000) == 5); static_assert(scale(mag_ratio<1, 60>, 120) == 2); // rational M (3/2 * 4 == 6): exact widened integer arithmetic (int64_t for int) static_assert(scale(mag_ratio<3, 2>, 4) == 6); // (1/3 * 9 == 3) static_assert(scale(mag_ratio<1, 3>, 9) == 3); // identity static_assert(scale(mag<1>, 42) == 42); // floating-point path static_assert(scale(mag_ratio<1, 2>, 1.0) == 0.5); static_assert(scale(mag<3>, 1.0f) == 3.0f); // MagnitudeScalable concept static_assert(detail::MagnitudeScalable); static_assert(detail::MagnitudeScalable); static_assert(detail::MagnitudeScalable); static_assert(detail::MagnitudeScalable); // Irrational magnitude conversions with integer representation require explicit value_cast. // deg = (π/180) rad — the conversion factor is irrational, so every integer result is approximate. // // Positive: value_cast compiles and produces the expected truncated integer result. static_assert(value_cast(1 * angular::radian).numerical_value_in(angular::degree) == 57); static_assert(value_cast(180 * angular::degree).numerical_value_in(angular::radian) == 3); // Negative: implicit conversion is blocked at compile time to prevent accidental precision loss. static_assert(!std::is_convertible_v, quantity>); static_assert(!std::is_convertible_v, quantity>); // Large-value safety: deg -> grad uses factor 10/9. Being a pure rational, the // computation uses exact 128-bit integer arithmetic — correct on all platforms, // including ARM / Apple Silicon where long double == double (64-bit mantissa). static_assert(value_cast(std::int64_t{1'000'000'000'000'000'000} * angular::degree) .numerical_value_in(angular::gradian) == std::int64_t{1'111'111'111'111'111'111}); } // namespace