00001 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 00002 /* 00003 * Copyright (c) 2006 INRIA 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation; 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 * 00018 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> 00019 */ 00020 #ifndef HIGH_PRECISION_128_H 00021 #define HIGH_PRECISION_128_H 00022 00023 #include <stdint.h> 00024 #include "cairo-wideint-private.h" 00025 00026 /** 00027 * This file contains an implementation of the HighPrecision class. 00028 * Each instance of the Time class also contains an instance of this 00029 * class which is used to perform all the arithmetic operations of 00030 * the Time class. 00031 * 00032 * This code is a bit ugly with a lot of inline methods for speed: 00033 * profiling this code on anything but the simplest scenarios shows 00034 * that it is a big bottleneck if great care in its implementation 00035 * is not performed. My observations are that what dominates are 00036 * Division operations (there are really really super costly) 00037 * and Comparison operations (because there are typically a lot of 00038 * these in any complex timekeeping code). 00039 * 00040 * So, the code tries really hard to perform any of these 128 bit 00041 * operations by doing all arithmetic on 64 bit integers when possible 00042 * (i.e., when there is no fractional part. This is a very common case). 00043 * Hence, the following code has a m_fastValue (64 bits) and a 00044 * m_slowValue (128 bits). m_fastValue is used by default and the code 00045 * converts it to a m_slowValue when needed. 00046 * 00047 * If you want to monitor the efficiency of this strategy, you can 00048 * enable the macro HP128INC below and call the HighPrecision::PrintStats 00049 * method at the end of the simulation. 00050 */ 00051 00052 00053 #define noGATHER_STATISTICS 1 00054 00055 #ifdef GATHER_STATISTICS 00056 #define HP128INC(x) x++ 00057 #else 00058 #define HP128INC(x) 00059 #endif 00060 00061 namespace ns3 { 00062 00063 class HighPrecision 00064 { 00065 public: 00066 inline HighPrecision (); 00067 inline HighPrecision (int64_t value, bool dummy); 00068 HighPrecision (double value); 00069 00070 static void PrintStats (void); 00071 00072 inline int64_t GetInteger (void) const; 00073 inline double GetDouble (void) const; 00074 inline bool Add (HighPrecision const &o); 00075 inline bool Sub (HighPrecision const &o); 00076 inline bool Mul (HighPrecision const &o); 00077 bool Div (HighPrecision const &o); 00078 00079 inline int Compare (HighPrecision const &o) const; 00080 inline static HighPrecision Zero (void); 00081 private: 00082 int64_t SlowGetInteger (void) const; 00083 double SlowGetDouble (void) const; 00084 bool SlowAdd (HighPrecision const &o); 00085 bool SlowSub (HighPrecision const &o); 00086 bool SlowMul (HighPrecision const &o); 00087 int SlowCompare (HighPrecision const &o) const; 00088 inline void EnsureSlow (void); 00089 00090 static const double MAX_64; 00091 bool m_isFast; 00092 int64_t m_fastValue; 00093 cairo_int128_t m_slowValue; 00094 00095 #ifdef GATHER_STATISTICS 00096 static int m_nfastadds; 00097 static int m_nfastsubs; 00098 static int m_nfastmuls; 00099 static int m_nfastcmps; 00100 static int m_nfastgets; 00101 static int m_nslowadds; 00102 static int m_nslowsubs; 00103 static int m_nslowmuls; 00104 static int m_nslowcmps; 00105 static int m_nslowgets; 00106 static int m_ndivs; 00107 static int m_nconversions; 00108 #endif /* GATHER_STATISTICS */ 00109 }; 00110 00111 }; // namespace ns3 00112 00113 namespace ns3 { 00114 00115 HighPrecision::HighPrecision () 00116 : m_isFast (true), 00117 m_fastValue (0) 00118 {} 00119 00120 HighPrecision::HighPrecision (int64_t value, bool dummy) 00121 : m_isFast (true), 00122 m_fastValue (value) 00123 {} 00124 00125 00126 int64_t 00127 HighPrecision::GetInteger (void) const 00128 { 00129 if (m_isFast) 00130 { 00131 HP128INC (m_nfastgets); 00132 return m_fastValue; 00133 } 00134 else 00135 { 00136 HP128INC (m_nslowgets); 00137 return SlowGetInteger (); 00138 } 00139 } 00140 double HighPrecision::GetDouble (void) const 00141 { 00142 if (m_isFast) 00143 { 00144 HP128INC (m_nfastgets); 00145 double retval = m_fastValue; 00146 return retval; 00147 } 00148 else 00149 { 00150 HP128INC (m_nslowgets); 00151 return SlowGetDouble (); 00152 } 00153 } 00154 bool 00155 HighPrecision::Add (HighPrecision const &o) 00156 { 00157 if (m_isFast && o.m_isFast) 00158 { 00159 HP128INC (m_nfastadds); 00160 m_fastValue += o.m_fastValue; 00161 return false; 00162 } 00163 else 00164 { 00165 HP128INC (m_nslowadds); 00166 return SlowAdd (o); 00167 } 00168 } 00169 bool 00170 HighPrecision::Sub (HighPrecision const &o) 00171 { 00172 if (m_isFast && o.m_isFast) 00173 { 00174 HP128INC (m_nfastsubs); 00175 m_fastValue -= o.m_fastValue; 00176 return false; 00177 } 00178 else 00179 { 00180 HP128INC (m_nslowsubs); 00181 return SlowSub (o); 00182 } 00183 } 00184 bool 00185 HighPrecision::Mul (HighPrecision const &o) 00186 { 00187 if (m_isFast && o.m_isFast) 00188 { 00189 HP128INC (m_nfastmuls); 00190 m_fastValue *= o.m_fastValue; 00191 return false; 00192 } 00193 else 00194 { 00195 HP128INC (m_nslowmuls); 00196 return SlowMul (o); 00197 } 00198 } 00199 00200 int 00201 HighPrecision::Compare (HighPrecision const &o) const 00202 { 00203 if (m_isFast && o.m_isFast) 00204 { 00205 HP128INC (m_nfastcmps); 00206 if (m_fastValue < o.m_fastValue) 00207 { 00208 return -1; 00209 } 00210 else if (m_fastValue == o.m_fastValue) 00211 { 00212 return 0; 00213 } 00214 else 00215 { 00216 return +1; 00217 } 00218 } 00219 else 00220 { 00221 HP128INC (m_nslowcmps); 00222 return SlowCompare (o); 00223 } 00224 // The below statement is unreachable but necessary for optimized 00225 // builds with gcc-4.0.x due to a compiler bug. 00226 return 0; 00227 } 00228 HighPrecision 00229 HighPrecision::Zero (void) 00230 { 00231 return HighPrecision (); 00232 } 00233 00234 00235 }; // namespace ns3 00236 00237 #endif /* HIGH_PRECISION_128_H */