Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:53:28

0001 
0002 //              Copyright Catch2 Authors
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //   (See accompanying file LICENSE.txt or copy at
0005 //        https://www.boost.org/LICENSE_1_0.txt)
0006 
0007 // SPDX-License-Identifier: BSL-1.0
0008 
0009 #ifndef CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
0010 #define CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
0011 
0012 #include <catch2/internal/catch_polyfills.hpp>
0013 
0014 #include <cassert>
0015 #include <cmath>
0016 #include <cstdint>
0017 #include <limits>
0018 #include <type_traits>
0019 
0020 namespace Catch {
0021 
0022     namespace Detail {
0023         /**
0024          * Returns the largest magnitude of 1-ULP distance inside the [a, b] range.
0025          *
0026          * Assumes `a < b`.
0027          */
0028         template <typename FloatType>
0029         FloatType gamma(FloatType a, FloatType b) {
0030             static_assert( std::is_floating_point<FloatType>::value,
0031                            "gamma returns the largest ULP magnitude within "
0032                            "floating point range [a, b]. This only makes sense "
0033                            "for floating point types" );
0034             assert( a <= b );
0035 
0036             const auto gamma_up = Catch::nextafter( a, std::numeric_limits<FloatType>::infinity() ) - a;
0037             const auto gamma_down = b - Catch::nextafter( b, -std::numeric_limits<FloatType>::infinity() );
0038 
0039             return gamma_up < gamma_down ? gamma_down : gamma_up;
0040         }
0041 
0042         template <typename FloatingPoint>
0043         struct DistanceTypePicker;
0044         template <>
0045         struct DistanceTypePicker<float> {
0046             using type = std::uint32_t;
0047         };
0048         template <>
0049         struct DistanceTypePicker<double> {
0050             using type = std::uint64_t;
0051         };
0052 
0053         template <typename T>
0054         using DistanceType = typename DistanceTypePicker<T>::type;
0055 
0056 #if defined( __GNUC__ ) || defined( __clang__ )
0057 #    pragma GCC diagnostic push
0058 #    pragma GCC diagnostic ignored "-Wfloat-equal"
0059 #endif
0060         /**
0061          * Computes the number of equi-distant floats in [a, b]
0062          *
0063          * Since not every range can be split into equidistant floats
0064          * exactly, we actually compute ceil(b/distance - a/distance),
0065          * because in those cases we want to overcount.
0066          *
0067          * Uses modified Dekker's FastTwoSum algorithm to handle rounding.
0068          */
0069         template <typename FloatType>
0070         DistanceType<FloatType>
0071         count_equidistant_floats( FloatType a, FloatType b, FloatType distance ) {
0072             assert( a <= b );
0073             // We get distance as gamma for our uniform float distribution,
0074             // so this will round perfectly.
0075             const auto ag = a / distance;
0076             const auto bg = b / distance;
0077 
0078             const auto s = bg - ag;
0079             const auto err = ( std::fabs( a ) <= std::fabs( b ) )
0080                                  ? -ag - ( s - bg )
0081                                  : bg - ( s + ag );
0082             const auto ceil_s = static_cast<DistanceType<FloatType>>( std::ceil( s ) );
0083 
0084             return ( ceil_s != s ) ? ceil_s : ceil_s + ( err > 0 );
0085         }
0086 #if defined( __GNUC__ ) || defined( __clang__ )
0087 #    pragma GCC diagnostic pop
0088 #endif
0089 
0090     }
0091 
0092 } // end namespace Catch
0093 
0094 #endif // CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED