Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-13 08:21:05

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4Log
0027 //
0028 // Class description:
0029 //
0030 // The basic idea is to exploit Pade polynomials.
0031 // A lot of ideas were inspired by the cephes math library
0032 // (by Stephen L. Moshier moshier@na-net.ornl.gov) as well as actual code.
0033 // The Cephes library can be found here:  http://www.netlib.org/cephes/
0034 // Code and algorithms for G4Exp have been extracted and adapted for Geant4
0035 // from the original implementation in the VDT mathematical library
0036 // (https://svnweb.cern.ch/trac/vdt), version 0.3.7.
0037 
0038 // Original implementation created on: Jun 23, 2012
0039 //      Author: Danilo Piparo, Thomas Hauth, Vincenzo Innocente
0040 //
0041 // --------------------------------------------------------------------
0042 /*
0043  * VDT is free software: you can redistribute it and/or modify
0044  * it under the terms of the GNU Lesser Public License as published by
0045  * the Free Software Foundation, either version 3 of the License, or
0046  * (at your option) any later version.
0047  *
0048  * This program is distributed in the hope that it will be useful,
0049  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0050  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0051  * GNU Lesser Public License for more details.
0052  *
0053  * You should have received a copy of the GNU Lesser Public License
0054  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0055  */
0056 // --------------------------------------------------------------------
0057 #ifndef G4HepEmLog_HH
0058 #define G4HepEmLog_HH 1
0059 
0060 /**
0061  * @file    G4HepEmLog.hh
0062  * @author  M. Novak
0063  * @date    2021
0064  *
0065  * @brief Just a copy of `G4Log` that's in fact a simplified version of VDT log.
0066  *
0067  * That's why the function names are `VDTLog` and `VDTLogf` for double and float.
0068  *
0069  */
0070 
0071 
0072 #ifdef WIN32
0073 
0074 #define VDTLog std::log
0075 
0076 #else
0077 
0078 #include <limits>
0079 #include <stdint.h>
0080 
0081 // local namespace for the constants/functions which are necessary only here
0082 //
0083 namespace DVTLogConsts {
0084   const double LOG_UPPER_LIMIT = 1e307;
0085   const double LOG_LOWER_LIMIT = 0;
0086 
0087   const double SQRTH  = 0.70710678118654752440;
0088   const float MAXNUMF = 3.4028234663852885981170418348451692544e38f;
0089 
0090   //----------------------------------------------------------------------------
0091   // Used to switch between different type of interpretations of the data
0092   // (64 bits)
0093   //
0094   union ieee754 {
0095     ieee754(){};
0096     ieee754(double thed) { d = thed; };
0097     ieee754(uint64_t thell) { ll = thell; };
0098     ieee754(float thef) { f[0] = thef; };
0099     ieee754(uint32_t thei) { i[0] = thei; };
0100     double d;
0101     float f[2];
0102     uint32_t i[2];
0103     uint64_t ll;
0104     uint16_t s[4];
0105   };
0106 
0107   inline double get_log_px(const double x) {
0108     const double PX1log = 1.01875663804580931796E-4;
0109     const double PX2log = 4.97494994976747001425E-1;
0110     const double PX3log = 4.70579119878881725854E0;
0111     const double PX4log = 1.44989225341610930846E1;
0112     const double PX5log = 1.79368678507819816313E1;
0113     const double PX6log = 7.70838733755885391666E0;
0114 
0115     double px = PX1log;
0116     px *= x;
0117     px += PX2log;
0118     px *= x;
0119     px += PX3log;
0120     px *= x;
0121     px += PX4log;
0122     px *= x;
0123     px += PX5log;
0124     px *= x;
0125     px += PX6log;
0126     return px;
0127   }
0128 
0129   inline double get_log_qx(const double x) {
0130     const double QX1log = 1.12873587189167450590E1;
0131     const double QX2log = 4.52279145837532221105E1;
0132     const double QX3log = 8.29875266912776603211E1;
0133     const double QX4log = 7.11544750618563894466E1;
0134     const double QX5log = 2.31251620126765340583E1;
0135 
0136     double qx = x;
0137     qx += QX1log;
0138     qx *= x;
0139     qx += QX2log;
0140     qx *= x;
0141     qx += QX3log;
0142     qx *= x;
0143     qx += QX4log;
0144     qx *= x;
0145     qx += QX5log;
0146     return qx;
0147   }
0148 
0149   //----------------------------------------------------------------------------
0150   // Converts a double to an unsigned long long
0151   //
0152   inline uint64_t dp2uint64(double x) {
0153     ieee754 tmp;
0154     tmp.d = x;
0155     return tmp.ll;
0156   }
0157 
0158   //----------------------------------------------------------------------------
0159   // Converts an unsigned long long to a double
0160   //
0161   inline double uint642dp(uint64_t ll) {
0162     ieee754 tmp;
0163     tmp.ll = ll;
0164     return tmp.d;
0165   }
0166 
0167   //----------------------------------------------------------------------------
0168   // Converts an int to a float
0169   //
0170   inline float uint322sp(int x) {
0171     ieee754 tmp;
0172     tmp.i[0] = x;
0173     return tmp.f[0];
0174   }
0175 
0176   //----------------------------------------------------------------------------
0177   // Converts a float to an int
0178   //
0179   inline uint32_t sp2uint32(float x)
0180   {
0181     ieee754 tmp;
0182     tmp.f[0] = x;
0183     return tmp.i[0];
0184   }
0185 
0186   //----------------------------------------------------------------------------
0187   /// Like frexp but vectorising and the exponent is a double.
0188   inline double getMantExponent(const double x, double& fe) {
0189     uint64_t n = dp2uint64(x);
0190 
0191     // Shift to the right up to the beginning of the exponent.
0192     // Then with a mask, cut off the sign bit
0193     uint64_t le = (n >> 52);
0194 
0195     // chop the head of the number: an int contains more than 11 bits (32)
0196     int32_t e =
0197       le;  // This is important since sums on uint64_t do not vectorise
0198     fe = e - 1023;
0199 
0200     // This puts to 11 zeroes the exponent
0201     n &= 0x800FFFFFFFFFFFFFULL;
0202     // build a mask which is 0.5, i.e. an exponent equal to 1022
0203     // which means *2, see the above +1.
0204     const uint64_t p05 = 0x3FE0000000000000ULL;  // dp2uint64(0.5);
0205     n |= p05;
0206 
0207     return uint642dp(n);
0208   }
0209 
0210   //----------------------------------------------------------------------------
0211   /// Like frexp but vectorising and the exponent is a float.
0212   inline float getMantExponentf(const float x, float& fe) {
0213     uint32_t n = sp2uint32(x);
0214     int32_t e  = (n >> 23) - 127;
0215     fe         = e;
0216 
0217     // fractional part
0218     const uint32_t p05f = 0x3f000000;  // //sp2uint32(0.5);
0219     n &= 0x807fffff;                   // ~0x7f800000;
0220     n |= p05f;
0221 
0222     return uint322sp(n);
0223   }
0224 }  // namespace DVTLogConsts
0225 
0226 // Log double precision --------------------------------------------------------
0227 
0228 inline double VDTLog(double x) {
0229   const double original_x = x;
0230 
0231   /* separate mantissa from exponent */
0232   double fe;
0233   x = DVTLogConsts::getMantExponent(x, fe);
0234 
0235   // blending
0236   x > DVTLogConsts::SQRTH ? fe += 1. : x += x;
0237   x -= 1.0;
0238 
0239   /* rational form */
0240   double px = DVTLogConsts::get_log_px(x);
0241 
0242   // for the final formula
0243   const double x2 = x * x;
0244   px *= x;
0245   px *= x2;
0246 
0247   const double qx = DVTLogConsts::get_log_qx(x);
0248 
0249   double res = px / qx;
0250 
0251   res -= fe * 2.121944400546905827679e-4;
0252   res -= 0.5 * x2;
0253 
0254   res = x + res;
0255   res += fe * 0.693359375;
0256 
0257   if(original_x > DVTLogConsts::LOG_UPPER_LIMIT)
0258     res = std::numeric_limits<double>::infinity();
0259   if(original_x < DVTLogConsts::LOG_LOWER_LIMIT)  // THIS IS NAN!
0260     res = -std::numeric_limits<double>::quiet_NaN();
0261 
0262   return res;
0263 }
0264 
0265 // Log single precision --------------------------------------------------------
0266 
0267 namespace DVTLogConsts {
0268   const float LOGF_UPPER_LIMIT = MAXNUMF;
0269   const float LOGF_LOWER_LIMIT = 0;
0270 
0271   const float PX1logf = 7.0376836292E-2f;
0272   const float PX2logf = -1.1514610310E-1f;
0273   const float PX3logf = 1.1676998740E-1f;
0274   const float PX4logf = -1.2420140846E-1f;
0275   const float PX5logf = 1.4249322787E-1f;
0276   const float PX6logf = -1.6668057665E-1f;
0277   const float PX7logf = 2.0000714765E-1f;
0278   const float PX8logf = -2.4999993993E-1f;
0279   const float PX9logf = 3.3333331174E-1f;
0280 
0281   inline float get_log_poly(const float x)
0282   {
0283     float y = x * PX1logf;
0284     y += PX2logf;
0285     y *= x;
0286     y += PX3logf;
0287     y *= x;
0288     y += PX4logf;
0289     y *= x;
0290     y += PX5logf;
0291     y *= x;
0292     y += PX6logf;
0293     y *= x;
0294     y += PX7logf;
0295     y *= x;
0296     y += PX8logf;
0297     y *= x;
0298     y += PX9logf;
0299     return y;
0300   }
0301 
0302   const float SQRTHF = 0.707106781186547524f;
0303 }  // namespace DVTLogConsts
0304 
0305 // Log single precision --------------------------------------------------------
0306 
0307 inline float VDTLogf(float x) {
0308   const float original_x = x;
0309 
0310   float fe;
0311   x = DVTLogConsts::getMantExponentf(x, fe);
0312 
0313   x > DVTLogConsts::SQRTHF ? fe += 1.f : x += x;
0314   x -= 1.0f;
0315 
0316   const float x2 = x * x;
0317 
0318   float res = DVTLogConsts::get_log_poly(x);
0319   res *= x2 * x;
0320 
0321   res += -2.12194440e-4f * fe;
0322   res += -0.5f * x2;
0323 
0324   res = x + res;
0325 
0326   res += 0.693359375f * fe;
0327 
0328   if(original_x > DVTLogConsts::LOGF_UPPER_LIMIT)
0329     res = std::numeric_limits<float>::infinity();
0330   if(original_x < DVTLogConsts::LOGF_LOWER_LIMIT)
0331     res = -std::numeric_limits<float>::quiet_NaN();
0332 
0333   return res;
0334 }
0335 
0336 //------------------------------------------------------------------------------
0337 
0338 void logv(const uint32_t size, double const* __restrict__ iarray,
0339           double* __restrict__ oarray);
0340 void logfv(const uint32_t size, float const* __restrict__ iarray,
0341            float* __restrict__ oarray);
0342 
0343 #endif // WIN32
0344 
0345 #endif // G4HepEmLog_HH