adevs_time.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /**
  2. * Copyright (c) 2013, James Nutaro
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  18. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. *
  25. * The views and conclusions contained in the software and documentation are those
  26. * of the authors and should not be interpreted as representing official policies,
  27. * either expressed or implied, of the FreeBSD Project.
  28. *
  29. * Bugs, comments, and questions can be sent to nutaro@gmail.com
  30. */
  31. #ifndef __adevs_time_h_
  32. #define __adevs_time_h_
  33. #include <cfloat>
  34. #include <iostream>
  35. #include <cmath>
  36. #include <limits>
  37. /// Returns the maximum value for a time type
  38. template <class T> inline T adevs_inf();
  39. /// Returns the zero value for a time type
  40. template <class T> inline T adevs_zero();
  41. /// Returns a value less than adevs_zero()
  42. template <class T> inline T adevs_sentinel();
  43. /// Returns the interval to the next instant of time
  44. template <class T> inline T adevs_epsilon();
  45. namespace adevs
  46. {
  47. /**
  48. * This time type allows models to evolve on R x Z.
  49. */
  50. template <typename T=double>
  51. class sd_time
  52. {
  53. public:
  54. /// Creates the identify (0,0)
  55. sd_time():t(0),k(0){}
  56. /// Create a time (t,k)
  57. sd_time(T t, int k):t(t),k(k){}
  58. /// Copy constructor
  59. sd_time(const sd_time& other):t(other.t),k(other.k){}
  60. /// Get the real part of time
  61. T real() const { return t; }
  62. /// Get the logical part of time
  63. double integer() const { return k; }
  64. /// Assignment operator
  65. const sd_time& operator=(const sd_time& other)
  66. {
  67. t = other.t;
  68. k = other.k;
  69. return *this;
  70. }
  71. /// Equivalence
  72. bool operator==(const sd_time& t2) const
  73. {
  74. return (t == t2.t && k == t2.k);
  75. }
  76. /// Not equal
  77. bool operator!=(const sd_time& t2) const
  78. {
  79. return !(*this == t2);
  80. }
  81. /// Order by t then by c
  82. bool operator<(const sd_time& t2) const
  83. {
  84. return (t < t2.t || (t == t2.t && k < t2.k));
  85. }
  86. /// Less than or equal
  87. bool operator<=(const sd_time& t2) const
  88. {
  89. return (*this == t2 || *this < t2);
  90. }
  91. /// Greater than
  92. bool operator>(const sd_time& t2) const
  93. {
  94. return !(*this <= t2);
  95. }
  96. /// Greater than or equal
  97. bool operator>=(const sd_time& t2) const
  98. {
  99. return !(*this < t2);
  100. }
  101. /// Advance this value by a step size t2
  102. sd_time operator+(const sd_time& t2) const
  103. {
  104. sd_time result(*this);
  105. result += t2;
  106. return result;
  107. }
  108. /// Advance this value by a step size t2
  109. const sd_time& operator+=(const sd_time& t2)
  110. {
  111. if (t2.t == 0) k += t2.k;
  112. else { t += t2.t; k = t2.k; }
  113. return *this;
  114. }
  115. /// Length of the interval from now to t2
  116. sd_time operator-(const sd_time& t2) const
  117. {
  118. sd_time result(*this);
  119. result -= t2;
  120. return result;
  121. }
  122. /// Length of the interval from now to t2
  123. const sd_time& operator-=(const sd_time& t2)
  124. {
  125. if (t == t2.t) { t = 0; k -= t2.k; }
  126. else t -= t2.t;
  127. return *this;
  128. }
  129. /// Print a time to the output stream
  130. friend std::ostream& operator<<(std::ostream& out, const sd_time& t)
  131. {
  132. out << "(" << t.t << "," << t.k << ")";
  133. return out;
  134. }
  135. /// Read a time from the input stream
  136. friend std::istream& operator>>(std::istream& in, sd_time& t)
  137. {
  138. char junk;
  139. in >> junk >> t.t >> junk >> t.k >> junk;
  140. return in;
  141. }
  142. private:
  143. T t; int k;
  144. };
  145. /**
  146. * <p>The fcmp() inline function is taken from fcmp.c, which is
  147. * Copyright (c) 1998-2000 Theodore C. Belding,
  148. * University of Michigan Center for the Study of Complex Systems,
  149. * <mailto:Ted.Belding@umich.edu>,
  150. * <http://www-personal.umich.edu/~streak/>,
  151. * </p>
  152. *
  153. * <p>This code is part of the fcmp distribution. fcmp is free software;
  154. * you can redistribute and modify it under the terms of the GNU Library
  155. * General Public License (LGPL), version 2 or later. This software
  156. * comes with absolutely no warranty.</p>
  157. */
  158. inline int fcmp(double x1, double x2, double epsilon)
  159. {
  160. int exponent;
  161. double delta;
  162. double difference;
  163. /* Get exponent(max(fabs(x1), fabs(x2))) and store it in exponent. */
  164. /* If neither x1 nor x2 is 0, */
  165. /* this is equivalent to max(exponent(x1), exponent(x2)). */
  166. /* If either x1 or x2 is 0, its exponent returned by frexp would be 0, */
  167. /* which is much larger than the exponents of numbers close to 0 in */
  168. /* magnitude. But the exponent of 0 should be less than any number */
  169. /* whose magnitude is greater than 0. */
  170. /* So we only want to set exponent to 0 if both x1 and */
  171. /* x2 are 0. Hence, the following works for all x1 and x2. */
  172. frexp(fabs(x1) > fabs(x2) ? x1 : x2, &exponent);
  173. /* Do the comparison. */
  174. /* delta = epsilon * pow(2, exponent) */
  175. /* Form a neighborhood around x2 of size delta in either direction. */
  176. /* If x1 is within this delta neighborhood of x2, x1 == x2. */
  177. /* Otherwise x1 > x2 or x1 < x2, depending on which side of */
  178. /* the neighborhood x1 is on. */
  179. delta = ldexp(epsilon, exponent);
  180. difference = x1 - x2;
  181. if (difference > delta)
  182. return 1; /* x1 > x2 */
  183. else if (difference < -delta)
  184. return -1; /* x1 < x2 */
  185. else /* -delta <= difference <= delta */
  186. return 0; /* x1 == x2 */
  187. }
  188. /**
  189. * This is an alternative double that may be used for the simulation clock
  190. * (i.e., as the template parameter T for models and simulators). It
  191. * uses the fcmp function to check for equality instead of the
  192. * default equality operator. Information on the fcmp function
  193. * may be found at http://fcmp.sourceforge.net/
  194. */
  195. class double_fcmp {
  196. private:
  197. double d;
  198. public:
  199. /**
  200. * The user must instantiate this static variable
  201. * and initialize as required by the fcmp function.
  202. */
  203. static double epsilon;
  204. double_fcmp(double rhs = 0)
  205. : d(rhs) { }
  206. const double_fcmp& operator=(const double_fcmp& rhs)
  207. {
  208. d = rhs.d;
  209. return *this;
  210. }
  211. const double_fcmp& operator=(double rhs)
  212. {
  213. d = rhs;
  214. return *this;
  215. }
  216. operator double()
  217. {
  218. return d;
  219. }
  220. bool operator<(double rhs) const
  221. {
  222. return (fcmp(d, rhs, epsilon) < 0);
  223. }
  224. bool operator<(const double_fcmp& rhs) const
  225. {
  226. return (fcmp(d, rhs.d, epsilon) < 0);
  227. }
  228. bool operator<=(const double_fcmp& rhs) const
  229. {
  230. return (fcmp(d, rhs.d, epsilon) <= 0);
  231. }
  232. bool operator>(const double_fcmp& rhs) const
  233. {
  234. return (fcmp(d, rhs.d, epsilon) > 0);
  235. }
  236. bool operator>=(const double_fcmp& rhs) const
  237. {
  238. return (fcmp(d, rhs.d, epsilon) >= 0);
  239. }
  240. bool operator==(double rhs) const
  241. {
  242. return (fcmp(d, rhs, epsilon) == 0);
  243. }
  244. bool operator==(const double_fcmp& rhs) const
  245. {
  246. return (fcmp(d, rhs.d, epsilon) == 0);
  247. }
  248. };
  249. } // end namespace
  250. template <> inline float adevs_inf() {
  251. return std::numeric_limits<float>::max(); }
  252. template <> inline long double adevs_inf() {
  253. return std::numeric_limits<long double>::max(); }
  254. template <> inline double adevs_inf() {
  255. return std::numeric_limits<double>::max(); }
  256. template <> inline int adevs_inf() {
  257. return std::numeric_limits<int>::max(); }
  258. template <> inline long adevs_inf() {
  259. return std::numeric_limits<long>::max(); }
  260. template <> inline adevs::double_fcmp adevs_inf() {
  261. return std::numeric_limits<double>::max(); }
  262. template <> inline adevs::sd_time<double> adevs_inf() {
  263. return adevs::sd_time<double>(std::numeric_limits<double>::max(),std::numeric_limits<int>::max()); }
  264. template <> inline adevs::sd_time<long> adevs_inf() {
  265. return adevs::sd_time<long>(std::numeric_limits<long>::max(),std::numeric_limits<int>::max()); }
  266. template <> inline adevs::sd_time<int> adevs_inf() {
  267. return adevs::sd_time<int>(std::numeric_limits<int>::max(),std::numeric_limits<int>::max()); }
  268. template <> inline float adevs_zero() { return 0.0f; }
  269. template <> inline long double adevs_zero() { return 0.0L; }
  270. template <> inline double adevs_zero() { return 0.0; }
  271. template <> inline int adevs_zero() { return 0; }
  272. template <> inline long adevs_zero() { return 0; }
  273. template <> inline adevs::double_fcmp adevs_zero() { return 0.0; }
  274. template <> inline adevs::sd_time<double> adevs_zero() { return adevs::sd_time<double>(0.0,0); }
  275. template <> inline adevs::sd_time<long> adevs_zero() { return adevs::sd_time<long>(0,0); }
  276. template <> inline adevs::sd_time<int> adevs_zero() { return adevs::sd_time<int>(0,0); }
  277. template <> inline float adevs_sentinel() { return -1.0f; }
  278. template <> inline long double adevs_sentinel() { return -1.0L; }
  279. template <> inline double adevs_sentinel() { return -1.0; }
  280. template <> inline int adevs_sentinel() { return -1; }
  281. template <> inline long adevs_sentinel() { return -1; }
  282. template <> inline adevs::double_fcmp adevs_sentinel() { return -1.0; }
  283. template <> inline adevs::sd_time<double> adevs_sentinel() { return adevs::sd_time<double>(-1.0,0); }
  284. template <> inline adevs::sd_time<long> adevs_sentinel() { return adevs::sd_time<long>(-1,0); }
  285. template <> inline adevs::sd_time<int> adevs_sentinel() { return adevs::sd_time<int>(-1,0); }
  286. template <> inline float adevs_epsilon() { return 0.0f; }
  287. template <> inline long double adevs_epsilon() { return 0.0L; }
  288. template <> inline double adevs_epsilon() { return 0.0; }
  289. template <> inline int adevs_epsilon() { return 0; }
  290. template <> inline long adevs_epsilon() { return 0; }
  291. template <> inline adevs::double_fcmp adevs_epsilon() { return 0.0; }
  292. template <> inline adevs::sd_time<double> adevs_epsilon() { return adevs::sd_time<double>(0.0,1); }
  293. template <> inline adevs::sd_time<long> adevs_epsilon() { return adevs::sd_time<long>(0,1); }
  294. template <> inline adevs::sd_time<int> adevs_epsilon() { return adevs::sd_time<int>(0,1); }
  295. #endif