rall2d.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*****************************************************************************
  2. * \file
  3. * class for automatic differentiation on scalar values and 1st
  4. * derivatives and 2nd derivative.
  5. *
  6. * Erwin Aertbelien, Div. PMA, Dep. of Mech. Eng., K.U.Leuven
  7. *
  8. * \version
  9. * ORO_Geometry V0.2
  10. *
  11. * \par Note
  12. * VC6++ contains a bug, concerning the use of inlined friend functions
  13. * in combination with namespaces. So, try to avoid inlined friend
  14. * functions !
  15. *
  16. * \par History
  17. * - $log$
  18. *
  19. * \par Release
  20. * $Name: $
  21. ****************************************************************************/
  22. #ifndef Rall2D_H
  23. #define Rall2D_H
  24. #include <math.h>
  25. #include <assert.h>
  26. #include "utility.h"
  27. namespace KDL {
  28. /**
  29. * Rall2d contains a value, and its gradient and its 2nd derivative, and defines an algebraic
  30. * structure on this pair.
  31. * This template class has 3 template parameters :
  32. * - T contains the type of the value.
  33. * - V contains the type of the gradient (can be a vector-like type).
  34. * - S defines a scalar type that can operate on Rall1d. This is the type that
  35. * is used to give back values of Norm() etc.
  36. *
  37. * S is usefull when you recurse a Rall1d object into itself to create a 2nd, 3th, 4th,..
  38. * derivatives. (e.g. Rall1d< Rall1d<double>, Rall1d<double>, double> ).
  39. *
  40. * S is always passed by value.
  41. *
  42. * \par Class Type
  43. * Concrete implementation
  44. */
  45. template <class T,class V=T,class S=T>
  46. class Rall2d
  47. {
  48. public :
  49. T t; //!< value
  50. V d; //!< 1st derivative
  51. V dd; //!< 2nd derivative
  52. public :
  53. // = Constructors
  54. INLINE Rall2d() {}
  55. explicit INLINE Rall2d(typename TI<T>::Arg c)
  56. {t=c;SetToZero(d);SetToZero(dd);}
  57. INLINE Rall2d(typename TI<T>::Arg tn,const V& afg):t(tn),d(afg) {SetToZero(dd);}
  58. INLINE Rall2d(typename TI<T>::Arg tn,const V& afg,const V& afg2):t(tn),d(afg),dd(afg2) {}
  59. // = Copy Constructor
  60. INLINE Rall2d(const Rall2d<T,V,S>& r):t(r.t),d(r.d),dd(r.dd) {}
  61. //if one defines this constructor, it's better optimized then the
  62. //automatically generated one ( that one set's up a loop to copy
  63. // word by word.
  64. // = Member functions to access internal structures :
  65. INLINE T& Value() {
  66. return t;
  67. }
  68. INLINE V& D() {
  69. return d;
  70. }
  71. INLINE V& DD() {
  72. return dd;
  73. }
  74. INLINE static Rall2d<T,V,S> Zero() {
  75. Rall2d<T,V,S> tmp;
  76. SetToZero(tmp);
  77. return tmp;
  78. }
  79. INLINE static Rall2d<T,V,S> Identity() {
  80. Rall2d<T,V,S> tmp;
  81. SetToIdentity(tmp);
  82. return tmp;
  83. }
  84. // = assignment operators
  85. INLINE Rall2d<T,V,S>& operator =(S c)
  86. {t=c;SetToZero(d);SetToZero(dd);return *this;}
  87. INLINE Rall2d<T,V,S>& operator =(const Rall2d<T,V,S>& r)
  88. {t=r.t;d=r.d;dd=r.dd;return *this;}
  89. INLINE Rall2d<T,V,S>& operator /=(const Rall2d<T,V,S>& rhs)
  90. {
  91. t /= rhs.t;
  92. d = (d-t*rhs.d)/rhs.t;
  93. dd= (dd - S(2)*d*rhs.d-t*rhs.dd)/rhs.t;
  94. return *this;
  95. }
  96. INLINE Rall2d<T,V,S>& operator *=(const Rall2d<T,V,S>& rhs)
  97. {
  98. t *= rhs.t;
  99. d = (d*rhs.t+t*rhs.d);
  100. dd = (dd*rhs.t+S(2)*d*rhs.d+t*rhs.dd);
  101. return *this;
  102. }
  103. INLINE Rall2d<T,V,S>& operator +=(const Rall2d<T,V,S>& rhs)
  104. {
  105. t +=rhs.t;
  106. d +=rhs.d;
  107. dd+=rhs.dd;
  108. return *this;
  109. }
  110. INLINE Rall2d<T,V,S>& operator -=(const Rall2d<T,V,S>& rhs)
  111. {
  112. t -= rhs.t;
  113. d -= rhs.d;
  114. dd -= rhs.dd;
  115. return *this;
  116. }
  117. INLINE Rall2d<T,V,S>& operator /=(S rhs)
  118. {
  119. t /= rhs;
  120. d /= rhs;
  121. dd /= rhs;
  122. return *this;
  123. }
  124. INLINE Rall2d<T,V,S>& operator *=(S rhs)
  125. {
  126. t *= rhs;
  127. d *= rhs;
  128. dd *= rhs;
  129. return *this;
  130. }
  131. INLINE Rall2d<T,V,S>& operator -=(S rhs)
  132. {
  133. t -= rhs;
  134. return *this;
  135. }
  136. INLINE Rall2d<T,V,S>& operator +=(S rhs)
  137. {
  138. t += rhs;
  139. return *this;
  140. }
  141. // = Operators between Rall2d objects
  142. /*
  143. friend INLINE Rall2d<T,V,S> operator /(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs);
  144. friend INLINE Rall2d<T,V,S> operator *(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs);
  145. friend INLINE Rall2d<T,V,S> operator +(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs);
  146. friend INLINE Rall2d<T,V,S> operator -(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs);
  147. friend INLINE Rall2d<T,V,S> operator -(const Rall2d<T,V,S>& arg);
  148. friend INLINE Rall2d<T,V,S> operator *(S s,const Rall2d<T,V,S>& v);
  149. friend INLINE Rall2d<T,V,S> operator *(const Rall2d<T,V,S>& v,S s);
  150. friend INLINE Rall2d<T,V,S> operator +(S s,const Rall2d<T,V,S>& v);
  151. friend INLINE Rall2d<T,V,S> operator +(const Rall2d<T,V,S>& v,S s);
  152. friend INLINE Rall2d<T,V,S> operator -(S s,const Rall2d<T,V,S>& v);
  153. friend INLINE INLINE Rall2d<T,V,S> operator -(const Rall2d<T,V,S>& v,S s);
  154. friend INLINE Rall2d<T,V,S> operator /(S s,const Rall2d<T,V,S>& v);
  155. friend INLINE Rall2d<T,V,S> operator /(const Rall2d<T,V,S>& v,S s);
  156. // = Mathematical functions that operate on Rall2d objects
  157. friend INLINE Rall2d<T,V,S> exp(const Rall2d<T,V,S>& arg);
  158. friend INLINE Rall2d<T,V,S> log(const Rall2d<T,V,S>& arg);
  159. friend INLINE Rall2d<T,V,S> sin(const Rall2d<T,V,S>& arg);
  160. friend INLINE Rall2d<T,V,S> cos(const Rall2d<T,V,S>& arg);
  161. friend INLINE Rall2d<T,V,S> tan(const Rall2d<T,V,S>& arg);
  162. friend INLINE Rall2d<T,V,S> sinh(const Rall2d<T,V,S>& arg);
  163. friend INLINE Rall2d<T,V,S> cosh(const Rall2d<T,V,S>& arg);
  164. friend INLINE Rall2d<T,V,S> tanh(const Rall2d<T,V,S>& arg);
  165. friend INLINE Rall2d<T,V,S> sqr(const Rall2d<T,V,S>& arg);
  166. friend INLINE Rall2d<T,V,S> pow(const Rall2d<T,V,S>& arg,double m) ;
  167. friend INLINE Rall2d<T,V,S> sqrt(const Rall2d<T,V,S>& arg);
  168. friend INLINE Rall2d<T,V,S> asin(const Rall2d<T,V,S>& arg);
  169. friend INLINE Rall2d<T,V,S> acos(const Rall2d<T,V,S>& arg);
  170. friend INLINE Rall2d<T,V,S> atan(const Rall2d<T,V,S>& x);
  171. friend INLINE Rall2d<T,V,S> atan2(const Rall2d<T,V,S>& y,const Rall2d<T,V,S>& x);
  172. friend INLINE Rall2d<T,V,S> abs(const Rall2d<T,V,S>& x);
  173. friend INLINE Rall2d<T,V,S> hypot(const Rall2d<T,V,S>& y,const Rall2d<T,V,S>& x);
  174. // returns sqrt(y*y+x*x), but is optimized for accuracy and speed.
  175. friend INLINE S Norm(const Rall2d<T,V,S>& value) ;
  176. // returns Norm( value.Value() ).
  177. // = Some utility functions to improve performance
  178. // (should also be declared on primitive types to improve uniformity
  179. friend INLINE Rall2d<T,V,S> LinComb(S alfa,const Rall2d<T,V,S>& a,
  180. TI<T>::Arg beta,const Rall2d<T,V,S>& b );
  181. friend INLINE void LinCombR(S alfa,const Rall2d<T,V,S>& a,
  182. TI<T>::Arg beta,const Rall2d<T,V,S>& b,Rall2d<T,V,S>& result );
  183. // = Setting value of a Rall2d object to 0 or 1
  184. friend INLINE void SetToZero(Rall2d<T,V,S>& value);
  185. friend INLINE void SetToOne(Rall2d<T,V,S>& value);
  186. // = Equality in an eps-interval
  187. friend INLINE bool Equal(const Rall2d<T,V,S>& y,const Rall2d<T,V,S>& x,double eps);
  188. */
  189. };
  190. // = Operators between Rall2d objects
  191. template <class T,class V,class S>
  192. INLINE Rall2d<T,V,S> operator /(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs)
  193. {
  194. Rall2d<T,V,S> tmp;
  195. tmp.t = lhs.t/rhs.t;
  196. tmp.d = (lhs.d-tmp.t*rhs.d)/rhs.t;
  197. tmp.dd= (lhs.dd-S(2)*tmp.d*rhs.d-tmp.t*rhs.dd)/rhs.t;
  198. return tmp;
  199. }
  200. template <class T,class V,class S>
  201. INLINE Rall2d<T,V,S> operator *(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs)
  202. {
  203. Rall2d<T,V,S> tmp;
  204. tmp.t = lhs.t*rhs.t;
  205. tmp.d = (lhs.d*rhs.t+lhs.t*rhs.d);
  206. tmp.dd = (lhs.dd*rhs.t+S(2)*lhs.d*rhs.d+lhs.t*rhs.dd);
  207. return tmp;
  208. }
  209. template <class T,class V,class S>
  210. INLINE Rall2d<T,V,S> operator +(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs)
  211. {
  212. return Rall2d<T,V,S>(lhs.t+rhs.t,lhs.d+rhs.d,lhs.dd+rhs.dd);
  213. }
  214. template <class T,class V,class S>
  215. INLINE Rall2d<T,V,S> operator -(const Rall2d<T,V,S>& lhs,const Rall2d<T,V,S>& rhs)
  216. {
  217. return Rall2d<T,V,S>(lhs.t-rhs.t,lhs.d-rhs.d,lhs.dd-rhs.dd);
  218. }
  219. template <class T,class V,class S>
  220. INLINE Rall2d<T,V,S> operator -(const Rall2d<T,V,S>& arg)
  221. {
  222. return Rall2d<T,V,S>(-arg.t,-arg.d,-arg.dd);
  223. }
  224. template <class T,class V,class S>
  225. INLINE Rall2d<T,V,S> operator *(S s,const Rall2d<T,V,S>& v)
  226. {
  227. return Rall2d<T,V,S>(s*v.t,s*v.d,s*v.dd);
  228. }
  229. template <class T,class V,class S>
  230. INLINE Rall2d<T,V,S> operator *(const Rall2d<T,V,S>& v,S s)
  231. {
  232. return Rall2d<T,V,S>(v.t*s,v.d*s,v.dd*s);
  233. }
  234. template <class T,class V,class S>
  235. INLINE Rall2d<T,V,S> operator +(S s,const Rall2d<T,V,S>& v)
  236. {
  237. return Rall2d<T,V,S>(s+v.t,v.d,v.dd);
  238. }
  239. template <class T,class V,class S>
  240. INLINE Rall2d<T,V,S> operator +(const Rall2d<T,V,S>& v,S s)
  241. {
  242. return Rall2d<T,V,S>(v.t+s,v.d,v.dd);
  243. }
  244. template <class T,class V,class S>
  245. INLINE Rall2d<T,V,S> operator -(S s,const Rall2d<T,V,S>& v)
  246. {
  247. return Rall2d<T,V,S>(s-v.t,-v.d,-v.dd);
  248. }
  249. template <class T,class V,class S>
  250. INLINE Rall2d<T,V,S> operator -(const Rall2d<T,V,S>& v,S s)
  251. {
  252. return Rall2d<T,V,S>(v.t-s,v.d,v.dd);
  253. }
  254. template <class T,class V,class S>
  255. INLINE Rall2d<T,V,S> operator /(S s,const Rall2d<T,V,S>& rhs)
  256. {
  257. Rall2d<T,V,S> tmp;
  258. tmp.t = s/rhs.t;
  259. tmp.d = (-tmp.t*rhs.d)/rhs.t;
  260. tmp.dd= (-S(2)*tmp.d*rhs.d-tmp.t*rhs.dd)/rhs.t;
  261. return tmp;
  262. }
  263. template <class T,class V,class S>
  264. INLINE Rall2d<T,V,S> operator /(const Rall2d<T,V,S>& v,S s)
  265. {
  266. return Rall2d<T,V,S>(v.t/s,v.d/s,v.dd/s);
  267. }
  268. template <class T,class V,class S>
  269. INLINE Rall2d<T,V,S> exp(const Rall2d<T,V,S>& arg)
  270. {
  271. Rall2d<T,V,S> tmp;
  272. tmp.t = exp(arg.t);
  273. tmp.d = tmp.t*arg.d;
  274. tmp.dd = tmp.d*arg.d+tmp.t*arg.dd;
  275. return tmp;
  276. }
  277. template <class T,class V,class S>
  278. INLINE Rall2d<T,V,S> log(const Rall2d<T,V,S>& arg)
  279. {
  280. Rall2d<T,V,S> tmp;
  281. tmp.t = log(arg.t);
  282. tmp.d = arg.d/arg.t;
  283. tmp.dd = (arg.dd-tmp.d*arg.d)/arg.t;
  284. return tmp;
  285. }
  286. template <class T,class V,class S>
  287. INLINE Rall2d<T,V,S> sin(const Rall2d<T,V,S>& arg)
  288. {
  289. T v1 = sin(arg.t);
  290. T v2 = cos(arg.t);
  291. return Rall2d<T,V,S>(v1,v2*arg.d,v2*arg.dd - (v1*arg.d)*arg.d );
  292. }
  293. template <class T,class V,class S>
  294. INLINE Rall2d<T,V,S> cos(const Rall2d<T,V,S>& arg)
  295. {
  296. T v1 = cos(arg.t);
  297. T v2 = -sin(arg.t);
  298. return Rall2d<T,V,S>(v1,v2*arg.d, v2*arg.dd - (v1*arg.d)*arg.d);
  299. }
  300. template <class T,class V,class S>
  301. INLINE Rall2d<T,V,S> tan(const Rall2d<T,V,S>& arg)
  302. {
  303. T v1 = tan(arg.t);
  304. T v2 = S(1)+sqr(v1);
  305. return Rall2d<T,V,S>(v1,v2*arg.d, v2*(arg.dd+(S(2)*v1*sqr(arg.d))));
  306. }
  307. template <class T,class V,class S>
  308. INLINE Rall2d<T,V,S> sinh(const Rall2d<T,V,S>& arg)
  309. {
  310. T v1 = sinh(arg.t);
  311. T v2 = cosh(arg.t);
  312. return Rall2d<T,V,S>(v1,v2*arg.d,v2*arg.dd + (v1*arg.d)*arg.d );
  313. }
  314. template <class T,class V,class S>
  315. INLINE Rall2d<T,V,S> cosh(const Rall2d<T,V,S>& arg)
  316. {
  317. T v1 = cosh(arg.t);
  318. T v2 = sinh(arg.t);
  319. return Rall2d<T,V,S>(v1,v2*arg.d,v2*arg.dd + (v1*arg.d)*arg.d );
  320. }
  321. template <class T,class V,class S>
  322. INLINE Rall2d<T,V,S> tanh(const Rall2d<T,V,S>& arg)
  323. {
  324. T v1 = tanh(arg.t);
  325. T v2 = S(1)-sqr(v1);
  326. return Rall2d<T,V,S>(v1,v2*arg.d, v2*(arg.dd-(S(2)*v1*sqr(arg.d))));
  327. }
  328. template <class T,class V,class S>
  329. INLINE Rall2d<T,V,S> sqr(const Rall2d<T,V,S>& arg)
  330. {
  331. return Rall2d<T,V,S>(arg.t*arg.t,
  332. (S(2)*arg.t)*arg.d,
  333. S(2)*(sqr(arg.d)+arg.t*arg.dd)
  334. );
  335. }
  336. template <class T,class V,class S>
  337. INLINE Rall2d<T,V,S> pow(const Rall2d<T,V,S>& arg,double m)
  338. {
  339. Rall2d<T,V,S> tmp;
  340. tmp.t = pow(arg.t,m);
  341. T v2 = (m/arg.t)*tmp.t;
  342. tmp.d = v2*arg.d;
  343. tmp.dd = (S((m-1))/arg.t)*tmp.d*arg.d + v2*arg.dd;
  344. return tmp;
  345. }
  346. template <class T,class V,class S>
  347. INLINE Rall2d<T,V,S> sqrt(const Rall2d<T,V,S>& arg)
  348. {
  349. /* By inversion of sqr(x) :*/
  350. Rall2d<T,V,S> tmp;
  351. tmp.t = sqrt(arg.t);
  352. tmp.d = (S(0.5)/tmp.t)*arg.d;
  353. tmp.dd = (S(0.5)*arg.dd-sqr(tmp.d))/tmp.t;
  354. return tmp;
  355. }
  356. template <class T,class V,class S>
  357. INLINE Rall2d<T,V,S> asin(const Rall2d<T,V,S>& arg)
  358. {
  359. /* By inversion of sin(x) */
  360. Rall2d<T,V,S> tmp;
  361. tmp.t = asin(arg.t);
  362. T v = cos(tmp.t);
  363. tmp.d = arg.d/v;
  364. tmp.dd = (arg.dd+arg.t*sqr(tmp.d))/v;
  365. return tmp;
  366. }
  367. template <class T,class V,class S>
  368. INLINE Rall2d<T,V,S> acos(const Rall2d<T,V,S>& arg)
  369. {
  370. /* By inversion of cos(x) */
  371. Rall2d<T,V,S> tmp;
  372. tmp.t = acos(arg.t);
  373. T v = -sin(tmp.t);
  374. tmp.d = arg.d/v;
  375. tmp.dd = (arg.dd+arg.t*sqr(tmp.d))/v;
  376. return tmp;
  377. }
  378. template <class T,class V,class S>
  379. INLINE Rall2d<T,V,S> atan(const Rall2d<T,V,S>& x)
  380. {
  381. /* By inversion of tan(x) */
  382. Rall2d<T,V,S> tmp;
  383. tmp.t = atan(x.t);
  384. T v = S(1)+sqr(x.t);
  385. tmp.d = x.d/v;
  386. tmp.dd = x.dd/v-(S(2)*x.t)*sqr(tmp.d);
  387. return tmp;
  388. }
  389. template <class T,class V,class S>
  390. INLINE Rall2d<T,V,S> atan2(const Rall2d<T,V,S>& y,const Rall2d<T,V,S>& x)
  391. {
  392. Rall2d<T,V,S> tmp;
  393. tmp.t = atan2(y.t,x.t);
  394. T v = sqr(y.t)+sqr(x.t);
  395. tmp.d = (x.t*y.d-x.d*y.t)/v;
  396. tmp.dd = ( x.t*y.dd-x.dd*y.t-S(2)*(x.t*x.d+y.t*y.d)*tmp.d ) / v;
  397. return tmp;
  398. }
  399. template <class T,class V,class S>
  400. INLINE Rall2d<T,V,S> abs(const Rall2d<T,V,S>& x)
  401. {
  402. T v(Sign(x));
  403. return Rall2d<T,V,S>(v*x,v*x.d,v*x.dd);
  404. }
  405. template <class T,class V,class S>
  406. INLINE Rall2d<T,V,S> hypot(const Rall2d<T,V,S>& y,const Rall2d<T,V,S>& x)
  407. {
  408. Rall2d<T,V,S> tmp;
  409. tmp.t = hypot(y.t,x.t);
  410. tmp.d = (x.t*x.d+y.t*y.d)/tmp.t;
  411. tmp.dd = (sqr(x.d)+x.t*x.dd+sqr(y.d)+y.t*y.dd-sqr(tmp.d))/tmp.t;
  412. return tmp;
  413. }
  414. // returns sqrt(y*y+x*x), but is optimized for accuracy and speed.
  415. template <class T,class V,class S>
  416. INLINE S Norm(const Rall2d<T,V,S>& value)
  417. {
  418. return Norm(value.t);
  419. }
  420. // returns Norm( value.Value() ).
  421. // (should also be declared on primitive types to improve uniformity
  422. template <class T,class V,class S>
  423. INLINE Rall2d<T,V,S> LinComb(S alfa,const Rall2d<T,V,S>& a,
  424. const T& beta,const Rall2d<T,V,S>& b ) {
  425. return Rall2d<T,V,S>(
  426. LinComb(alfa,a.t,beta,b.t),
  427. LinComb(alfa,a.d,beta,b.d),
  428. LinComb(alfa,a.dd,beta,b.dd)
  429. );
  430. }
  431. template <class T,class V,class S>
  432. INLINE void LinCombR(S alfa,const Rall2d<T,V,S>& a,
  433. const T& beta,const Rall2d<T,V,S>& b,Rall2d<T,V,S>& result ) {
  434. LinCombR(alfa, a.t, beta, b.t, result.t);
  435. LinCombR(alfa, a.d, beta, b.d, result.d);
  436. LinCombR(alfa, a.dd, beta, b.dd, result.dd);
  437. }
  438. template <class T,class V,class S>
  439. INLINE void SetToZero(Rall2d<T,V,S>& value)
  440. {
  441. SetToZero(value.t);
  442. SetToZero(value.d);
  443. SetToZero(value.dd);
  444. }
  445. template <class T,class V,class S>
  446. INLINE void SetToIdentity(Rall2d<T,V,S>& value)
  447. {
  448. SetToZero(value.d);
  449. SetToIdentity(value.t);
  450. SetToZero(value.dd);
  451. }
  452. template <class T,class V,class S>
  453. INLINE bool Equal(const Rall2d<T,V,S>& y,const Rall2d<T,V,S>& x,double eps=epsilon)
  454. {
  455. return (Equal(x.t,y.t,eps)&&
  456. Equal(x.d,y.d,eps)&&
  457. Equal(x.dd,y.dd,eps)
  458. );
  459. }
  460. }
  461. #endif