Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:08:51

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 #ifndef CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
0009 #define CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
0010 
0011 #include <catch2/internal/catch_polyfills.hpp>
0012 
0013 #include <cassert>
0014 #include <cmath>
0015 #include <cstdint>
0016 #include <utility>
0017 #include <limits>
0018 
0019 namespace Catch {
0020     namespace Detail {
0021 
0022         uint32_t convertToBits(float f);
0023         uint64_t convertToBits(double d);
0024 
0025         // Used when we know we want == comparison of two doubles
0026         // to centralize warning suppression
0027         bool directCompare( float lhs, float rhs );
0028         bool directCompare( double lhs, double rhs );
0029 
0030     } // end namespace Detail
0031 
0032 
0033 
0034 #if defined( __GNUC__ ) || defined( __clang__ )
0035 #    pragma GCC diagnostic push
0036     // We do a bunch of direct compensations of floating point numbers,
0037     // because we know what we are doing and actually do want the direct
0038     // comparison behaviour.
0039 #    pragma GCC diagnostic ignored "-Wfloat-equal"
0040 #endif
0041 
0042     /**
0043      * Calculates the ULP distance between two floating point numbers
0044      *
0045      * The ULP distance of two floating point numbers is the count of
0046      * valid floating point numbers representable between them.
0047      *
0048      * There are some exceptions between how this function counts the
0049      * distance, and the interpretation of the standard as implemented.
0050      * by e.g. `nextafter`. For this function it always holds that:
0051      * * `(x == y) => ulpDistance(x, y) == 0` (so `ulpDistance(-0, 0) == 0`)
0052      * * `ulpDistance(maxFinite, INF) == 1`
0053      * * `ulpDistance(x, -x) == 2 * ulpDistance(x, 0)`
0054      *
0055      * \pre `!isnan( lhs )`
0056      * \pre `!isnan( rhs )`
0057      * \pre floating point numbers are represented in IEEE-754 format
0058      */
0059     template <typename FP>
0060     uint64_t ulpDistance( FP lhs, FP rhs ) {
0061         assert( std::numeric_limits<FP>::is_iec559 &&
0062             "ulpDistance assumes IEEE-754 format for floating point types" );
0063         assert( !Catch::isnan( lhs ) &&
0064                 "Distance between NaN and number is not meaningful" );
0065         assert( !Catch::isnan( rhs ) &&
0066                 "Distance between NaN and number is not meaningful" );
0067 
0068         // We want X == Y to imply 0 ULP distance even if X and Y aren't
0069         // bit-equal (-0 and 0), or X - Y != 0 (same sign infinities).
0070         if ( lhs == rhs ) { return 0; }
0071 
0072         // We need a properly typed positive zero for type inference.
0073         static constexpr FP positive_zero{};
0074 
0075         // We want to ensure that +/- 0 is always represented as positive zero
0076         if ( lhs == positive_zero ) { lhs = positive_zero; }
0077         if ( rhs == positive_zero ) { rhs = positive_zero; }
0078 
0079         // If arguments have different signs, we can handle them by summing
0080         // how far are they from 0 each.
0081         if ( std::signbit( lhs ) != std::signbit( rhs ) ) {
0082             return ulpDistance( std::abs( lhs ), positive_zero ) +
0083                    ulpDistance( std::abs( rhs ), positive_zero );
0084         }
0085 
0086         // When both lhs and rhs are of the same sign, we can just
0087         // read the numbers bitwise as integers, and then subtract them
0088         // (assuming IEEE).
0089         uint64_t lc = Detail::convertToBits( lhs );
0090         uint64_t rc = Detail::convertToBits( rhs );
0091 
0092         // The ulp distance between two numbers is symmetric, so to avoid
0093         // dealing with overflows we want the bigger converted number on the lhs
0094         if ( lc < rc ) {
0095             std::swap( lc, rc );
0096         }
0097 
0098         return lc - rc;
0099     }
0100 
0101 #if defined( __GNUC__ ) || defined( __clang__ )
0102 #    pragma GCC diagnostic pop
0103 #endif
0104 
0105 
0106 } // end namespace Catch
0107 
0108 #endif // CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED