Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 08:53:53

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/math/Constant.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <type_traits>
0010 
0011 #include "corecel/Macros.hh"
0012 
0013 namespace celeritas
0014 {
0015 //---------------------------------------------------------------------------//
0016 /*!
0017  * Full-precision floating point constant with automatic precision demotion.
0018  *
0019  * We want two behaviors from constants in Celeritas:
0020  * 1. They don't accidentally promote runtime arithmetic from single to double
0021  *    precision when compiling at a lower precision. This incurs a substantial
0022  *    performance penalty on GPU.
0023  * 2. We can use their full double-precision values when we need to: either in
0024  *    templated code or when interacting with other libraries. (For example,
0025  *    float(pi) > pi which can lead to errors in Geant4.)
0026  *
0027  * This class stores a full-precision (double) value as its "real type" and
0028  * defines explicit conversion operators that allow it to automatically convert
0029  * to a lower-precision or real-precision type.
0030  *
0031  * Operations with a floating point value returns a value of that precision
0032  * (performed at that precision level); operations with integers return a
0033  * full-precision Constant; and operations with Constants return a Constant.
0034  */
0035 class Constant
0036 {
0037   public:
0038     //!@{
0039     //! \name Type aliases
0040     using real_type = double;
0041     //!@}
0042 
0043   public:
0044     //! Explicitly construct from a full-precision value
0045     explicit CELER_CONSTEXPR_FUNCTION Constant(real_type v) : value_{v} {}
0046 
0047     //! Access the value explicitly
0048     CELER_CONSTEXPR_FUNCTION real_type value() const { return value_; }
0049 
0050     //! Explicit conversion of stored value
0051     explicit CELER_CONSTEXPR_FUNCTION operator float() const { return value_; }
0052     //! Explicit access to stored value
0053     explicit CELER_CONSTEXPR_FUNCTION operator double() const
0054     {
0055         return value_;
0056     }
0057 
0058   private:
0059     real_type value_;
0060 };
0061 
0062 //! Unary negation
0063 CELER_CONSTEXPR_FUNCTION Constant operator-(Constant lhs) noexcept
0064 {
0065     return Constant{-lhs.value()};
0066 }
0067 
0068 //---------------------------------------------------------------------------//
0069 //! \cond
0070 #define CELER_DEFINE_CONSTANT_CMP(TOKEN)                                          \
0071     template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> \
0072     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(Constant lhs, T rhs) noexcept    \
0073     {                                                                             \
0074         return static_cast<T>(lhs.value()) TOKEN rhs;                             \
0075     }                                                                             \
0076     template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> \
0077     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(T lhs, Constant rhs) noexcept    \
0078     {                                                                             \
0079         return lhs TOKEN static_cast<T>(rhs.value());                             \
0080     }                                                                             \
0081     template<class T, std::enable_if_t<std::is_integral_v<T>, bool> = true>       \
0082     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(Constant lhs, T rhs) noexcept    \
0083     {                                                                             \
0084         return lhs.value() TOKEN static_cast<Constant::real_type>(rhs);           \
0085     }                                                                             \
0086     template<class T, std::enable_if_t<std::is_integral_v<T>, bool> = true>       \
0087     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(T lhs, Constant rhs) noexcept    \
0088     {                                                                             \
0089         return static_cast<Constant::real_type>(lhs) TOKEN rhs.value();           \
0090     }                                                                             \
0091     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(Constant lhs,                    \
0092                                                  Constant rhs) noexcept           \
0093     {                                                                             \
0094         return lhs.value() TOKEN rhs.value();                                     \
0095     }
0096 
0097 //!@{
0098 //! Comparison for Constant
0099 CELER_DEFINE_CONSTANT_CMP(==)
0100 CELER_DEFINE_CONSTANT_CMP(!=)
0101 CELER_DEFINE_CONSTANT_CMP(<)
0102 CELER_DEFINE_CONSTANT_CMP(>)
0103 CELER_DEFINE_CONSTANT_CMP(<=)
0104 CELER_DEFINE_CONSTANT_CMP(>=)
0105 //!@}
0106 
0107 #undef CELER_DEFINE_CONSTANT_CMP
0108 
0109 //!@{
0110 //! Arithmetic for Constant
0111 #define CELER_DEFINE_CONSTANT_OP(TOKEN)                                           \
0112     template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> \
0113     CELER_CONSTEXPR_FUNCTION T operator TOKEN(Constant lhs, T rhs) noexcept       \
0114     {                                                                             \
0115         return static_cast<T>(lhs.value()) TOKEN rhs;                             \
0116     }                                                                             \
0117     template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> \
0118     CELER_CONSTEXPR_FUNCTION T operator TOKEN(T lhs, Constant rhs) noexcept       \
0119     {                                                                             \
0120         return lhs TOKEN static_cast<T>(rhs.value());                             \
0121     }                                                                             \
0122     template<class T, std::enable_if_t<std::is_integral_v<T>, bool> = true>       \
0123     CELER_CONSTEXPR_FUNCTION Constant operator TOKEN(Constant lhs,                \
0124                                                      T rhs) noexcept              \
0125     {                                                                             \
0126         return Constant{lhs.value() TOKEN rhs};                                   \
0127     }                                                                             \
0128     template<class T, std::enable_if_t<std::is_integral_v<T>, bool> = true>       \
0129     CELER_CONSTEXPR_FUNCTION Constant operator TOKEN(T lhs,                       \
0130                                                      Constant rhs) noexcept       \
0131     {                                                                             \
0132         return Constant{lhs TOKEN rhs.value()};                                   \
0133     }                                                                             \
0134     CELER_CONSTEXPR_FUNCTION Constant operator TOKEN(Constant lhs,                \
0135                                                      Constant rhs) noexcept       \
0136     {                                                                             \
0137         return Constant{lhs.value() TOKEN rhs.value()};                           \
0138     }
0139 
0140 CELER_DEFINE_CONSTANT_OP(*)
0141 CELER_DEFINE_CONSTANT_OP(/)
0142 CELER_DEFINE_CONSTANT_OP(+)
0143 CELER_DEFINE_CONSTANT_OP(-)
0144 //!@!}
0145 
0146 #undef CELER_DEFINE_CONSTANT_OP
0147 
0148 //!@{
0149 //! In-place arithmetic for Constant
0150 #define CELER_DEFINE_CONSTANT_OP(TOKEN)                                           \
0151     template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> \
0152     CELER_CONSTEXPR_FUNCTION T& operator TOKEN(T & lhs, Constant rhs) noexcept    \
0153     {                                                                             \
0154         return lhs TOKEN static_cast<T>(rhs.value());                             \
0155     }
0156 
0157 CELER_DEFINE_CONSTANT_OP(*=)
0158 CELER_DEFINE_CONSTANT_OP(/=)
0159 CELER_DEFINE_CONSTANT_OP(+=)
0160 CELER_DEFINE_CONSTANT_OP(-=)
0161 //!@!}
0162 
0163 #undef CELER_DEFINE_CONSTANT_OP
0164 
0165 //! \endcond
0166 //---------------------------------------------------------------------------//
0167 }  // namespace celeritas