diff --git a/include/bound/cmath.hpp b/include/bound/cmath.hpp index e4dc508..e0ace78 100644 --- a/include/bound/cmath.hpp +++ b/include/bound/cmath.hpp @@ -1215,7 +1215,7 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return sqrt_signed_impl(x); #elif defined(BND_MATH_FLOAT) - float v = static_cast(static_cast(x)); + float v = flt::to_float(x); if (v < 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; return slim::expected{flt::store(flt::detail::d_sqrt(v))}; @@ -1292,7 +1292,7 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return pow_base_impl(x); #elif defined(BND_MATH_FLOAT) - return flt::store(flt::detail::d_pow(static_cast(Base), static_cast(static_cast(x)))); + return flt::store(flt::detail::d_pow(static_cast(Base), flt::to_float(x))); #else return dbl::store(dbl::detail::d_pow(static_cast(Base), static_cast(x))); #endif @@ -1385,7 +1385,7 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return tan_impl(angle); #elif defined(BND_MATH_FLOAT) - float x = static_cast(static_cast(angle)); + float x = flt::to_float(angle); float c = flt::detail::d_cos(x); if (c == 0.0f) return slim::expected{slim::unexpected(errc::division_by_zero)}; @@ -1508,7 +1508,7 @@ namespace bnd::math constexpr int W = detail::working_bits(); out = detail::sin_slot(bnd::detail::raw_imax(angle)); #elif defined(BND_MATH_FLOAT) - out = flt::detail::d_sin(static_cast(static_cast(angle)) * (flt::detail::kPi / 180.0f)); + out = flt::detail::d_sin(flt::to_float(angle) * (flt::detail::kPi / 180.0f)); #else out = dbl::detail::d_sin(static_cast(angle) * (dbl::detail::kPi / 180.0)); #endif @@ -1524,7 +1524,7 @@ namespace bnd::math constexpr int W = detail::working_bits(); out = detail::sin_slot(bnd::detail::raw_imax(angle) + M / 4); #elif defined(BND_MATH_FLOAT) - out = flt::detail::d_cos(static_cast(static_cast(angle)) * (flt::detail::kPi / 180.0f)); + out = flt::detail::d_cos(flt::to_float(angle) * (flt::detail::kPi / 180.0f)); #else out = dbl::detail::d_cos(static_cast(angle) * (dbl::detail::kPi / 180.0)); #endif @@ -1546,7 +1546,7 @@ namespace bnd::math out = (detail::sin_slot(i) / c).value(); // sin / cos return true; #elif defined(BND_MATH_FLOAT) - float rad = static_cast(static_cast(angle)) * (flt::detail::kPi / 180.0f); + float rad = flt::to_float(angle) * (flt::detail::kPi / 180.0f); float c = flt::detail::d_cos(rad); if (c == 0.0f) return false; // pole out = flt::detail::d_sin(rad) / c; @@ -2025,10 +2025,10 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return pow_impl(base, exp); #elif defined(BND_MATH_FLOAT) - float b = static_cast(static_cast(base)); + float b = flt::to_float(base); if (b <= 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; - float r = flt::detail::d_pow(b, static_cast(static_cast(exp))); + float r = flt::detail::d_pow(b, flt::to_float(exp)); if constexpr (!has_flag(BoundPolicy, clamp)) // clamp Out: saturate below if (r < static_cast(static_cast(Lower)) || r > static_cast(static_cast(Upper))) return slim::expected{slim::unexpected(errc::overflow)}; @@ -2327,7 +2327,7 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap()); using Out = bnd::math::detail::sqrt_signed_auto_t; - float v = static_cast(static_cast(x)); + float v = flt::to_float(x); if (v < 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; return slim::expected{store(detail::d_sqrt(v))}; @@ -2362,7 +2362,7 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap()); using Out = bnd::math::detail::pow_base_auto_t; - return store(detail::d_pow(static_cast(Base), static_cast(static_cast(x)))); + return store(detail::d_pow(static_cast(Base), flt::to_float(x))); } template @@ -2378,7 +2378,7 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap()); using Out = bnd::math::detail::tan_auto_t; - float x = static_cast(static_cast(angle)); + float x = flt::to_float(angle); float c = detail::d_cos(x); if (c == 0.0f) return slim::expected{slim::unexpected(errc::division_by_zero)}; @@ -2442,10 +2442,10 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap() && bnd::math::detail::require_snap()); using Out = bnd::math::detail::pow_auto_t; - float b = static_cast(static_cast(base)); + float b = flt::to_float(base); if (b <= 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; - float r = detail::d_pow(b, static_cast(static_cast(exp))); + float r = detail::d_pow(b, flt::to_float(exp)); if constexpr (!has_flag(BoundPolicy, clamp)) // clamp Out: saturate below if (r < static_cast(static_cast(Lower)) || r > static_cast(static_cast(Upper))) return slim::expected{slim::unexpected(errc::overflow)}; diff --git a/include/bound/cmath_float.hpp b/include/bound/cmath_float.hpp index a881db0..6da10c6 100644 --- a/include/bound/cmath_float.hpp +++ b/include/bound/cmath_float.hpp @@ -234,42 +234,54 @@ namespace bnd::math::flt else { Out o{}; o = bnd::detail::rational{static_cast(f)}; return o; } } + // Read an input bound as `float`. An f32-backed operand IS a binary32 raw, so + // read it directly — no double hop (keeps the whole flt+f32 path in hardware + // float on a single-precision FPU). Any other storage decodes via double then + // narrows; float→double→float round-trips to the same float, so this is a pure + // optimization with no value change. + template + [[nodiscard]] BND_DBL_FN float to_float(In x) + { + if constexpr (bnd::detail::f32_raw) return x.raw(); + else return static_cast(static_cast(x)); + } + template - [[nodiscard]] BND_DBL_FN Out sin_core(In x) { return store(detail::d_sin(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out sin_core(In x) { return store(detail::d_sin(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out cos_core(In x) { return store(detail::d_cos(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out cos_core(In x) { return store(detail::d_cos(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out exp_core(In x) { return store(detail::d_exp(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out exp_core(In x) { return store(detail::d_exp(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out sqrt_core(In x) { return store(detail::d_sqrt(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out sqrt_core(In x) { return store(detail::d_sqrt(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out log_core(In x) { return store(detail::d_log(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out log_core(In x) { return store(detail::d_log(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out exp2_core(In x) { return store(detail::d_exp2(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out exp2_core(In x) { return store(detail::d_exp2(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out log2_core(In x) { return store(detail::d_log2(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out log2_core(In x) { return store(detail::d_log2(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out log10_core(In x){ return store(detail::d_log10(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out log10_core(In x){ return store(detail::d_log10(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out cbrt_core(In x) { return store(detail::d_cbrt(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out cbrt_core(In x) { return store(detail::d_cbrt(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out sinh_core(In x) { return store(detail::d_sinh(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out sinh_core(In x) { return store(detail::d_sinh(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out cosh_core(In x) { return store(detail::d_cosh(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out cosh_core(In x) { return store(detail::d_cosh(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out tanh_core(In x) { return store(detail::d_tanh(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out tanh_core(In x) { return store(detail::d_tanh(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out atan_core(In x) { return store(detail::d_atan(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out atan_core(In x) { return store(detail::d_atan(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out asin_core(In x) { return store(detail::d_asin(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out asin_core(In x) { return store(detail::d_asin(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out acos_core(In x) { return store(detail::d_acos(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out acos_core(In x) { return store(detail::d_acos(to_float(x))); } template [[nodiscard]] BND_DBL_FN Out atan2_core(In y, In x) - { return store(detail::d_atan2(static_cast(static_cast(y)), static_cast(static_cast(x)))); } + { return store(detail::d_atan2(to_float(y), to_float(x))); } template [[nodiscard]] BND_DBL_FN Out hypot_core(InX x, InY y) - { return store(detail::d_hypot(static_cast(static_cast(x)), static_cast(static_cast(y)))); } + { return store(detail::d_hypot(to_float(x), to_float(y))); } } // namespace bnd::math::flt #endif // !BND_MATH_NO_FP diff --git a/single_include/bound/bound.hpp b/single_include/bound/bound.hpp index 6c2ec7f..2ea68da 100644 --- a/single_include/bound/bound.hpp +++ b/single_include/bound/bound.hpp @@ -8296,42 +8296,54 @@ namespace bnd::math::flt else { Out o{}; o = bnd::detail::rational{static_cast(f)}; return o; } } + // Read an input bound as `float`. An f32-backed operand IS a binary32 raw, so + // read it directly — no double hop (keeps the whole flt+f32 path in hardware + // float on a single-precision FPU). Any other storage decodes via double then + // narrows; float→double→float round-trips to the same float, so this is a pure + // optimization with no value change. + template + [[nodiscard]] BND_DBL_FN float to_float(In x) + { + if constexpr (bnd::detail::f32_raw) return x.raw(); + else return static_cast(static_cast(x)); + } + template - [[nodiscard]] BND_DBL_FN Out sin_core(In x) { return store(detail::d_sin(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out sin_core(In x) { return store(detail::d_sin(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out cos_core(In x) { return store(detail::d_cos(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out cos_core(In x) { return store(detail::d_cos(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out exp_core(In x) { return store(detail::d_exp(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out exp_core(In x) { return store(detail::d_exp(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out sqrt_core(In x) { return store(detail::d_sqrt(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out sqrt_core(In x) { return store(detail::d_sqrt(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out log_core(In x) { return store(detail::d_log(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out log_core(In x) { return store(detail::d_log(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out exp2_core(In x) { return store(detail::d_exp2(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out exp2_core(In x) { return store(detail::d_exp2(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out log2_core(In x) { return store(detail::d_log2(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out log2_core(In x) { return store(detail::d_log2(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out log10_core(In x){ return store(detail::d_log10(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out log10_core(In x){ return store(detail::d_log10(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out cbrt_core(In x) { return store(detail::d_cbrt(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out cbrt_core(In x) { return store(detail::d_cbrt(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out sinh_core(In x) { return store(detail::d_sinh(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out sinh_core(In x) { return store(detail::d_sinh(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out cosh_core(In x) { return store(detail::d_cosh(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out cosh_core(In x) { return store(detail::d_cosh(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out tanh_core(In x) { return store(detail::d_tanh(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out tanh_core(In x) { return store(detail::d_tanh(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out atan_core(In x) { return store(detail::d_atan(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out atan_core(In x) { return store(detail::d_atan(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out asin_core(In x) { return store(detail::d_asin(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out asin_core(In x) { return store(detail::d_asin(to_float(x))); } template - [[nodiscard]] BND_DBL_FN Out acos_core(In x) { return store(detail::d_acos(static_cast(static_cast(x)))); } + [[nodiscard]] BND_DBL_FN Out acos_core(In x) { return store(detail::d_acos(to_float(x))); } template [[nodiscard]] BND_DBL_FN Out atan2_core(In y, In x) - { return store(detail::d_atan2(static_cast(static_cast(y)), static_cast(static_cast(x)))); } + { return store(detail::d_atan2(to_float(y), to_float(x))); } template [[nodiscard]] BND_DBL_FN Out hypot_core(InX x, InY y) - { return store(detail::d_hypot(static_cast(static_cast(x)), static_cast(static_cast(y)))); } + { return store(detail::d_hypot(to_float(x), to_float(y))); } } // namespace bnd::math::flt #endif // !BND_MATH_NO_FP @@ -9541,7 +9553,7 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return sqrt_signed_impl(x); #elif defined(BND_MATH_FLOAT) - float v = static_cast(static_cast(x)); + float v = flt::to_float(x); if (v < 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; return slim::expected{flt::store(flt::detail::d_sqrt(v))}; @@ -9618,7 +9630,7 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return pow_base_impl(x); #elif defined(BND_MATH_FLOAT) - return flt::store(flt::detail::d_pow(static_cast(Base), static_cast(static_cast(x)))); + return flt::store(flt::detail::d_pow(static_cast(Base), flt::to_float(x))); #else return dbl::store(dbl::detail::d_pow(static_cast(Base), static_cast(x))); #endif @@ -9711,7 +9723,7 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return tan_impl(angle); #elif defined(BND_MATH_FLOAT) - float x = static_cast(static_cast(angle)); + float x = flt::to_float(angle); float c = flt::detail::d_cos(x); if (c == 0.0f) return slim::expected{slim::unexpected(errc::division_by_zero)}; @@ -9834,7 +9846,7 @@ namespace bnd::math constexpr int W = detail::working_bits(); out = detail::sin_slot(bnd::detail::raw_imax(angle)); #elif defined(BND_MATH_FLOAT) - out = flt::detail::d_sin(static_cast(static_cast(angle)) * (flt::detail::kPi / 180.0f)); + out = flt::detail::d_sin(flt::to_float(angle) * (flt::detail::kPi / 180.0f)); #else out = dbl::detail::d_sin(static_cast(angle) * (dbl::detail::kPi / 180.0)); #endif @@ -9850,7 +9862,7 @@ namespace bnd::math constexpr int W = detail::working_bits(); out = detail::sin_slot(bnd::detail::raw_imax(angle) + M / 4); #elif defined(BND_MATH_FLOAT) - out = flt::detail::d_cos(static_cast(static_cast(angle)) * (flt::detail::kPi / 180.0f)); + out = flt::detail::d_cos(flt::to_float(angle) * (flt::detail::kPi / 180.0f)); #else out = dbl::detail::d_cos(static_cast(angle) * (dbl::detail::kPi / 180.0)); #endif @@ -9872,7 +9884,7 @@ namespace bnd::math out = (detail::sin_slot(i) / c).value(); // sin / cos return true; #elif defined(BND_MATH_FLOAT) - float rad = static_cast(static_cast(angle)) * (flt::detail::kPi / 180.0f); + float rad = flt::to_float(angle) * (flt::detail::kPi / 180.0f); float c = flt::detail::d_cos(rad); if (c == 0.0f) return false; // pole out = flt::detail::d_sin(rad) / c; @@ -10351,10 +10363,10 @@ namespace bnd::math #if defined(BND_MATH_NO_FP) return pow_impl(base, exp); #elif defined(BND_MATH_FLOAT) - float b = static_cast(static_cast(base)); + float b = flt::to_float(base); if (b <= 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; - float r = flt::detail::d_pow(b, static_cast(static_cast(exp))); + float r = flt::detail::d_pow(b, flt::to_float(exp)); if constexpr (!has_flag(BoundPolicy, clamp)) // clamp Out: saturate below if (r < static_cast(static_cast(Lower)) || r > static_cast(static_cast(Upper))) return slim::expected{slim::unexpected(errc::overflow)}; @@ -10653,7 +10665,7 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap()); using Out = bnd::math::detail::sqrt_signed_auto_t; - float v = static_cast(static_cast(x)); + float v = flt::to_float(x); if (v < 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; return slim::expected{store(detail::d_sqrt(v))}; @@ -10688,7 +10700,7 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap()); using Out = bnd::math::detail::pow_base_auto_t; - return store(detail::d_pow(static_cast(Base), static_cast(static_cast(x)))); + return store(detail::d_pow(static_cast(Base), flt::to_float(x))); } template @@ -10704,7 +10716,7 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap()); using Out = bnd::math::detail::tan_auto_t; - float x = static_cast(static_cast(angle)); + float x = flt::to_float(angle); float c = detail::d_cos(x); if (c == 0.0f) return slim::expected{slim::unexpected(errc::division_by_zero)}; @@ -10768,10 +10780,10 @@ namespace bnd::math { static_assert(bnd::math::detail::require_snap() && bnd::math::detail::require_snap()); using Out = bnd::math::detail::pow_auto_t; - float b = static_cast(static_cast(base)); + float b = flt::to_float(base); if (b <= 0.0f) return slim::expected{slim::unexpected(errc::domain_error)}; - float r = detail::d_pow(b, static_cast(static_cast(exp))); + float r = detail::d_pow(b, flt::to_float(exp)); if constexpr (!has_flag(BoundPolicy, clamp)) // clamp Out: saturate below if (r < static_cast(static_cast(Lower)) || r > static_cast(static_cast(Upper))) return slim::expected{slim::unexpected(errc::overflow)};