Simbody
3.4 (development)
|
00001 #ifndef SimTK_SIMMATRIX_SCALAR_H_ 00002 #define SimTK_SIMMATRIX_SCALAR_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2005-12 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00033 #include "SimTKcommon/internal/common.h" 00034 #include "SimTKcommon/Constants.h" 00035 #include "SimTKcommon/internal/Exception.h" 00036 #include "SimTKcommon/internal/ExceptionMacros.h" 00037 #include "SimTKcommon/internal/String.h" 00038 #include "SimTKcommon/internal/Array.h" 00039 00040 #include "SimTKcommon/internal/conjugate.h" 00041 #include "SimTKcommon/internal/CompositeNumericalTypes.h" 00042 #include "SimTKcommon/internal/NTraits.h" 00043 #include "SimTKcommon/internal/negator.h" 00044 00045 #include <complex> 00046 #include <cmath> 00047 #include <climits> 00048 #include <cassert> 00049 #include <utility> 00050 00051 namespace SimTK { 00052 00054 // Handy default-precision definitions // 00056 00057 typedef conjugate<Real> Conjugate; // like Complex 00058 00091 extern SimTK_SimTKCOMMON_EXPORT const Real NaN; 00095 extern SimTK_SimTKCOMMON_EXPORT const Real Infinity; 00096 00100 extern SimTK_SimTKCOMMON_EXPORT const Real Eps; 00104 extern SimTK_SimTKCOMMON_EXPORT const Real SqrtEps; 00110 extern SimTK_SimTKCOMMON_EXPORT const Real TinyReal; 00115 extern SimTK_SimTKCOMMON_EXPORT const Real SignificantReal; 00116 00119 extern SimTK_SimTKCOMMON_EXPORT const Real LeastPositiveReal; 00123 extern SimTK_SimTKCOMMON_EXPORT const Real MostPositiveReal; 00126 extern SimTK_SimTKCOMMON_EXPORT const Real LeastNegativeReal; 00130 extern SimTK_SimTKCOMMON_EXPORT const Real MostNegativeReal; 00131 00135 extern SimTK_SimTKCOMMON_EXPORT const int NumDigitsReal; 00136 00142 extern SimTK_SimTKCOMMON_EXPORT const int LosslessNumDigitsReal; // double ~20, 00143 // float ~9 00144 00145 // Carefully calculated constants, with convenient memory addresses. 00146 00147 extern SimTK_SimTKCOMMON_EXPORT const Real Zero; 00148 extern SimTK_SimTKCOMMON_EXPORT const Real One; 00149 extern SimTK_SimTKCOMMON_EXPORT const Real MinusOne; 00150 extern SimTK_SimTKCOMMON_EXPORT const Real Two; 00151 extern SimTK_SimTKCOMMON_EXPORT const Real Three; 00152 00153 extern SimTK_SimTKCOMMON_EXPORT const Real OneHalf; 00154 extern SimTK_SimTKCOMMON_EXPORT const Real OneThird; 00155 extern SimTK_SimTKCOMMON_EXPORT const Real OneFourth; 00156 extern SimTK_SimTKCOMMON_EXPORT const Real OneFifth; 00157 extern SimTK_SimTKCOMMON_EXPORT const Real OneSixth; 00158 extern SimTK_SimTKCOMMON_EXPORT const Real OneSeventh; 00159 extern SimTK_SimTKCOMMON_EXPORT const Real OneEighth; 00160 extern SimTK_SimTKCOMMON_EXPORT const Real OneNinth; 00161 extern SimTK_SimTKCOMMON_EXPORT const Real Pi; 00162 extern SimTK_SimTKCOMMON_EXPORT const Real OneOverPi; 00163 extern SimTK_SimTKCOMMON_EXPORT const Real E; 00164 extern SimTK_SimTKCOMMON_EXPORT const Real Log2E; 00165 extern SimTK_SimTKCOMMON_EXPORT const Real Log10E; 00166 extern SimTK_SimTKCOMMON_EXPORT const Real Sqrt2; 00167 extern SimTK_SimTKCOMMON_EXPORT const Real OneOverSqrt2; 00168 extern SimTK_SimTKCOMMON_EXPORT const Real Sqrt3; 00169 extern SimTK_SimTKCOMMON_EXPORT const Real OneOverSqrt3; 00170 extern SimTK_SimTKCOMMON_EXPORT const Real CubeRoot2; 00171 extern SimTK_SimTKCOMMON_EXPORT const Real CubeRoot3; 00172 extern SimTK_SimTKCOMMON_EXPORT const Real Ln2; 00173 extern SimTK_SimTKCOMMON_EXPORT const Real Ln10; 00174 00180 extern SimTK_SimTKCOMMON_EXPORT const Complex I; 00183 00184 // SOME SCALAR UTILITIES // 00186 00187 00201 // We use the trick that v & v-1 returns the value that is v with its 00202 // rightmost bit cleared (if it has a rightmost bit set). 00203 inline bool atMostOneBitIsSet(unsigned char v) {return (v&(v-1))==0;} 00204 inline bool atMostOneBitIsSet(unsigned short v) {return (v&(v-1))==0;} 00205 inline bool atMostOneBitIsSet(unsigned int v) {return (v&(v-1))==0;} 00206 inline bool atMostOneBitIsSet(unsigned long v) {return (v&(v-1))==0;} 00207 inline bool atMostOneBitIsSet(unsigned long long v) {return (v&(v-1))==0;} 00208 inline bool atMostOneBitIsSet(signed char v) {return (v&(v-1))==0;} 00209 inline bool atMostOneBitIsSet(char v) {return (v&(v-1))==0;} 00210 inline bool atMostOneBitIsSet(short v) {return (v&(v-1))==0;} 00211 inline bool atMostOneBitIsSet(int v) {return (v&(v-1))==0;} 00212 inline bool atMostOneBitIsSet(long v) {return (v&(v-1))==0;} 00213 inline bool atMostOneBitIsSet(long long v) {return (v&(v-1))==0;} 00215 00230 inline bool exactlyOneBitIsSet(unsigned char v) {return v && atMostOneBitIsSet(v);} 00231 inline bool exactlyOneBitIsSet(unsigned short v) {return v && atMostOneBitIsSet(v);} 00232 inline bool exactlyOneBitIsSet(unsigned int v) {return v && atMostOneBitIsSet(v);} 00233 inline bool exactlyOneBitIsSet(unsigned long v) {return v && atMostOneBitIsSet(v);} 00234 inline bool exactlyOneBitIsSet(unsigned long long v) {return v && atMostOneBitIsSet(v);} 00235 inline bool exactlyOneBitIsSet(signed char v) {return v && atMostOneBitIsSet(v);} 00236 inline bool exactlyOneBitIsSet(char v) {return v && atMostOneBitIsSet(v);} 00237 inline bool exactlyOneBitIsSet(short v) {return v && atMostOneBitIsSet(v);} 00238 inline bool exactlyOneBitIsSet(int v) {return v && atMostOneBitIsSet(v);} 00239 inline bool exactlyOneBitIsSet(long v) {return v && atMostOneBitIsSet(v);} 00240 inline bool exactlyOneBitIsSet(long long v) {return v && atMostOneBitIsSet(v);} 00242 00269 00270 inline bool signBit(unsigned char u) {return false;} 00271 inline bool signBit(unsigned short u) {return false;} 00272 inline bool signBit(unsigned int u) {return false;} 00273 inline bool signBit(unsigned long u) {return false;} 00274 inline bool signBit(unsigned long long u) {return false;} 00275 00276 // Note that plain 'char' type is not overloaded -- see above. 00277 00278 // We're assuming sizeof(char)==1, short==2, int==4, long long==8 which is safe 00279 // for all our anticipated platforms. But some 64 bit implementations have 00280 // sizeof(long)==4 while others have sizeof(long)==8 so we'll use the ANSI 00281 // standard value LONG_MIN which is a long value with just the high bit set. 00282 // (We're assuming two's complement integers here; I haven't seen anything 00283 // else in decades.) 00284 inline bool signBit(signed char i) {return ((unsigned char)i & 0x80U) != 0;} 00285 inline bool signBit(short i) {return ((unsigned short)i & 0x8000U) != 0;} 00286 inline bool signBit(int i) {return ((unsigned int)i & 0x80000000U) != 0;} 00287 inline bool signBit(long long i) {return ((unsigned long long)i & 0x8000000000000000ULL) != 0;} 00288 00289 inline bool signBit(long i) {return ((unsigned long)i 00290 & (unsigned long)LONG_MIN) != 0;} 00291 00292 inline bool signBit(const float& f) {return std::signbit(f);} 00293 inline bool signBit(const double& d) {return std::signbit(d);} 00294 inline bool signBit(const negator<float>& nf) {return std::signbit(-nf);} // !! 00295 inline bool signBit(const negator<double>& nd) {return std::signbit(-nd);} // !! 00296 00311 inline unsigned int sign(unsigned char u) {return u==0 ? 0 : 1;} 00312 inline unsigned int sign(unsigned short u) {return u==0 ? 0 : 1;} 00313 inline unsigned int sign(unsigned int u) {return u==0 ? 0 : 1;} 00314 inline unsigned int sign(unsigned long u) {return u==0 ? 0 : 1;} 00315 inline unsigned int sign(unsigned long long u) {return u==0 ? 0 : 1;} 00316 00317 // Don't overload for plain "char" because it may be signed or unsigned 00318 // depending on the compiler. 00319 00320 inline int sign(signed char i) {return i>0 ? 1 : (i<0 ? -1 : 0);} 00321 inline int sign(short i) {return i>0 ? 1 : (i<0 ? -1 : 0);} 00322 inline int sign(int i) {return i>0 ? 1 : (i<0 ? -1 : 0);} 00323 inline int sign(long i) {return i>0 ? 1 : (i<0 ? -1 : 0);} 00324 inline int sign(long long i) {return i>0 ? 1 : (i<0 ? -1 : 0);} 00325 00326 inline int sign(const float& x) {return x>0 ? 1 : (x<0 ? -1 : 0);} 00327 inline int sign(const double& x) {return x>0 ? 1 : (x<0 ? -1 : 0);} 00328 inline int sign(const long double& x) {return x>0 ? 1 : (x<0 ? -1 : 0);} 00329 00330 inline int sign(const negator<float>& x) {return -sign(-x);} // -x is free 00331 inline int sign(const negator<double>& x) {return -sign(-x);} 00332 inline int sign(const negator<long double>& x) {return -sign(-x);} 00334 00351 inline unsigned char square(unsigned char u) {return u*u;} 00352 inline unsigned short square(unsigned short u) {return u*u;} 00353 inline unsigned int square(unsigned int u) {return u*u;} 00354 inline unsigned long square(unsigned long u) {return u*u;} 00355 inline unsigned long long square(unsigned long long u) {return u*u;} 00356 00357 inline char square(char c) {return c*c;} 00358 00359 inline signed char square(signed char i) {return i*i;} 00360 inline short square(short i) {return i*i;} 00361 inline int square(int i) {return i*i;} 00362 inline long square(long i) {return i*i;} 00363 inline long long square(long long i) {return i*i;} 00364 00365 inline float square(const float& x) {return x*x;} 00366 inline double square(const double& x) {return x*x;} 00367 inline long double square(const long double& x) {return x*x;} 00368 00369 // Negation is free for negators, so we can square them and clean 00370 // them up at the same time at no extra cost. 00371 inline float square(const negator<float>& x) {return square(-x);} 00372 inline double square(const negator<double>& x) {return square(-x);} 00373 inline long double square(const negator<long double>& x) {return square(-x);} 00374 00375 // It is safer to templatize using complex classes, and doesn't make 00376 // debugging any worse since complex is already templatized. 00377 // 5 flops vs. 6 for general complex multiply. 00378 template <class P> inline 00379 std::complex<P> square(const std::complex<P>& x) { 00380 const P re=x.real(), im=x.imag(); 00381 return std::complex<P>(re*re-im*im, 2*re*im); 00382 } 00383 00384 // We can square a conjugate and clean it up back to complex at 00385 // the same time at zero cost (or maybe 1 negation depending 00386 // on how the compiler handles the "-2" below). 00387 template <class P> inline 00388 std::complex<P> square(const conjugate<P>& x) { 00389 const P re=x.real(), nim=x.negImag(); 00390 return std::complex<P>(re*re-nim*nim, -2*re*nim); 00391 } 00392 00393 template <class P> inline 00394 std::complex<P> square(const negator< std::complex<P> >& x) { 00395 return square(-x); // negation is free for negators 00396 } 00397 00398 // Note return type here after squaring negator<conjugate> 00399 // is complex, not conjugate. 00400 template <class P> inline 00401 std::complex<P> square(const negator< conjugate<P> >& x) { 00402 return square(-x); // negation is free for negators 00403 } 00405 00424 inline unsigned char cube(unsigned char u) {return u*u*u;} 00425 inline unsigned short cube(unsigned short u) {return u*u*u;} 00426 inline unsigned int cube(unsigned int u) {return u*u*u;} 00427 inline unsigned long cube(unsigned long u) {return u*u*u;} 00428 inline unsigned long long cube(unsigned long long u) {return u*u*u;} 00429 00430 inline char cube(char c) {return c*c*c;} 00431 00432 inline signed char cube(signed char i) {return i*i*i;} 00433 inline short cube(short i) {return i*i*i;} 00434 inline int cube(int i) {return i*i*i;} 00435 inline long cube(long i) {return i*i*i;} 00436 inline long long cube(long long i) {return i*i*i;} 00437 00438 inline float cube(const float& x) {return x*x*x;} 00439 inline double cube(const double& x) {return x*x*x;} 00440 inline long double cube(const long double& x) {return x*x*x;} 00441 00442 // To keep this cheap we'll defer getting rid of the negator<> until 00443 // some other operation. We cube -x and then recast that to negator<> 00444 // on return, for a total cost of 2 flops. 00445 inline negator<float> cube(const negator<float>& x) { 00446 return negator<float>::recast(cube(-x)); 00447 } 00448 inline negator<double> cube(const negator<double>& x) { 00449 return negator<double>::recast(cube(-x)); 00450 } 00451 inline negator<long double> cube(const negator<long double>& x) { 00452 return negator<long double>::recast(cube(-x)); 00453 } 00454 00455 // Cubing a complex this way is cheaper than doing it by 00456 // multiplication. Cost here is 8 flops vs. 11 for a square 00457 // followed by a multiply. 00458 template <class P> inline 00459 std::complex<P> cube(const std::complex<P>& x) { 00460 const P re=x.real(), im=x.imag(), rr=re*re, ii=im*im; 00461 return std::complex<P>(re*(rr-3*ii), im*(3*rr-ii)); 00462 } 00463 00464 // Cubing a negated complex allows us to cube and eliminate the 00465 // negator at the same time for zero extra cost. Compare the 00466 // expressions here to the normal cube above to see the free 00467 // sign changes in both parts. 8 flops here. 00468 template <class P> inline 00469 std::complex<P> cube(const negator< std::complex<P> >& x) { 00470 // -x is free for a negator 00471 const P nre=(-x).real(), nim=(-x).imag(), rr=nre*nre, ii=nim*nim; 00472 return std::complex<P>(nre*(3*ii-rr), nim*(ii-3*rr)); 00473 } 00474 00475 // Cubing a conjugate this way saves a lot over multiplying, and 00476 // also lets us convert the result to complex for free. 00477 template <class P> inline 00478 std::complex<P> cube(const conjugate<P>& x) { 00479 const P re=x.real(), nim=x.negImag(), rr=re*re, ii=nim*nim; 00480 return std::complex<P>(re*(rr-3*ii), nim*(ii-3*rr)); 00481 } 00482 00483 00484 // Cubing a negated conjugate this way saves a lot over multiplying, and 00485 // also lets us convert the result to non-negated complex for free. 00486 template <class P> inline 00487 std::complex<P> cube(const negator< conjugate<P> >& x) { 00488 // -x is free for a negator 00489 const P nre=(-x).real(), im=(-x).negImag(), rr=nre*nre, ii=im*im; 00490 return std::complex<P>(nre*(3*ii-rr), im*(3*rr-ii)); 00491 } 00493 00525 00541 inline double& clampInPlace(double low, double& v, double high) 00542 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00544 inline float& clampInPlace(float low, float& v, float high) 00545 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00547 inline long double& clampInPlace(long double low, long double& v, long double high) 00548 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00549 00550 // Floating point clamps with integer bounds; without these 00551 // explicit casts are required. 00552 00555 inline double& clampInPlace(int low, double& v, int high) 00556 { return clampInPlace((double)low,v,(double)high); } 00559 inline float& clampInPlace(int low, float& v, int high) 00560 { return clampInPlace((float)low,v,(float)high); } 00563 inline long double& clampInPlace(int low, long double& v, int high) 00564 { return clampInPlace((long double)low,v,(long double)high); } 00565 00568 inline double& clampInPlace(int low, double& v, double high) 00569 { return clampInPlace((double)low,v,high); } 00572 inline float& clampInPlace(int low, float& v, float high) 00573 { return clampInPlace((float)low,v,high); } 00576 inline long double& clampInPlace(int low, long double& v, long double high) 00577 { return clampInPlace((long double)low,v,high); } 00578 00581 inline double& clampInPlace(double low, double& v, int high) 00582 { return clampInPlace(low,v,(double)high); } 00585 inline float& clampInPlace(float low, float& v, int high) 00586 { return clampInPlace(low,v,(float)high); } 00589 inline long double& clampInPlace(long double low, long double& v, int high) 00590 { return clampInPlace(low,v,(long double)high); } 00591 00593 inline unsigned char& clampInPlace(unsigned char low, unsigned char& v, unsigned char high) 00594 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00596 inline unsigned short& clampInPlace(unsigned short low, unsigned short& v, unsigned short high) 00597 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00599 inline unsigned int& clampInPlace(unsigned int low, unsigned int& v, unsigned int high) 00600 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00602 inline unsigned long& clampInPlace(unsigned long low, unsigned long& v, unsigned long high) 00603 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00605 inline unsigned long long& clampInPlace(unsigned long long low, unsigned long long& v, unsigned long long high) 00606 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00607 00609 inline char& clampInPlace(char low, char& v, char high) 00610 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00612 inline signed char& clampInPlace(signed char low, signed char& v, signed char high) 00613 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00614 00616 inline short& clampInPlace(short low, short& v, short high) 00617 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00619 inline int& clampInPlace(int low, int& v, int high) 00620 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00622 inline long& clampInPlace(long low, long& v, long high) 00623 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00625 inline long long& clampInPlace(long long low, long long& v, long long high) 00626 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00627 00629 inline negator<float>& clampInPlace(float low, negator<float>& v, float high) 00630 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00632 inline negator<double>& clampInPlace(double low, negator<double>& v, double high) 00633 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00635 inline negator<long double>& clampInPlace(long double low, negator<long double>& v, long double high) 00636 { assert(low<=high); if (v<low) v=low; else if (v>high) v=high; return v; } 00637 00638 00639 00660 inline double clamp(double low, double v, double high) 00661 { return clampInPlace(low,v,high); } 00663 inline float clamp(float low, float v, float high) 00664 { return clampInPlace(low,v,high); } 00666 inline long double clamp(long double low, long double v, long double high) 00667 { return clampInPlace(low,v,high); } 00668 00671 inline double clamp(int low, double v, int high) 00672 { return clampInPlace(low,v,high); } 00675 inline float clamp(int low, float v, int high) 00676 { return clampInPlace(low,v,high); } 00679 inline long double clamp(int low, long double v, int high) 00680 { return clampInPlace(low,v,high); } 00681 00684 inline double clamp(int low, double v, double high) 00685 { return clampInPlace(low,v,high); } 00688 inline float clamp(int low, float v, float high) 00689 { return clampInPlace(low,v,high); } 00692 inline long double clamp(int low, long double v, long double high) 00693 { return clampInPlace(low,v,high); } 00694 00697 inline double clamp(double low, double v, int high) 00698 { return clampInPlace(low,v,high); } 00701 inline float clamp(float low, float v, int high) 00702 { return clampInPlace(low,v,high); } 00705 inline long double clamp(long double low, long double v, int high) 00706 { return clampInPlace(low,v,high); } 00707 00709 inline unsigned char clamp(unsigned char low, unsigned char v, unsigned char high) 00710 { return clampInPlace(low,v,high); } 00712 inline unsigned short clamp(unsigned short low, unsigned short v, unsigned short high) 00713 { return clampInPlace(low,v,high); } 00715 inline unsigned int clamp(unsigned int low, unsigned int v, unsigned int high) 00716 { return clampInPlace(low,v,high); } 00718 inline unsigned long clamp(unsigned long low, unsigned long v, unsigned long high) 00719 { return clampInPlace(low,v,high); } 00721 inline unsigned long long clamp(unsigned long long low, unsigned long long v, unsigned long long high) 00722 { return clampInPlace(low,v,high); } 00723 00725 inline char clamp(char low, char v, char high) 00726 { return clampInPlace(low,v,high); } 00728 inline signed char clamp(signed char low, signed char v, signed char high) 00729 { return clampInPlace(low,v,high); } 00730 00732 inline short clamp(short low, short v, short high) 00733 { return clampInPlace(low,v,high); } 00735 inline int clamp(int low, int v, int high) 00736 { return clampInPlace(low,v,high); } 00738 inline long clamp(long low, long v, long high) 00739 { return clampInPlace(low,v,high); } 00741 inline long long clamp(long long low, long long v, long long high) 00742 { return clampInPlace(low,v,high); } 00743 00744 00745 // These aren't strictly necessary but are here to help the 00746 // compiler find the right overload to call. These cost an 00747 // extra flop because the negator<T> has to be cast to T which 00748 // requires that the pending negation be performed. Note that 00749 // the result types are not negated. 00750 00755 inline float clamp(float low, negator<float> v, float high) 00756 { return clamp(low,(float)v,high); } 00761 inline double clamp(double low, negator<double> v, double high) 00762 { return clamp(low,(double)v,high); } 00767 inline long double clamp(long double low, negator<long double> v, long double high) 00768 { return clamp(low,(long double)v,high); } 00809 00824 inline double stepUp(double x) 00825 { assert(0 <= x && x <= 1); 00826 return x*x*x*(10+x*(6*x-15)); } //10x^3-15x^4+6x^5 00827 00828 00843 inline double stepDown(double x) {return 1.0 -stepUp(x);} 00844 00845 00920 inline double stepAny(double y0, double yRange, 00921 double x0, double oneOverXRange, 00922 double x) 00923 { double xadj = (x-x0)*oneOverXRange; 00924 assert(-NTraits<double>::getSignificant() <= xadj 00925 && xadj <= 1 + NTraits<double>::getSignificant()); 00926 clampInPlace(0.0,xadj,1.0); 00927 return y0 + yRange*stepUp(xadj); } 00928 00932 inline double dstepUp(double x) { 00933 assert(0 <= x && x <= 1); 00934 const double xxm1=x*(x-1); 00935 return 30*xxm1*xxm1; //30x^2-60x^3+30x^4 00936 } 00937 00941 inline double dstepDown(double x) {return -dstepUp(x);} 00942 00946 inline double dstepAny(double yRange, 00947 double x0, double oneOverXRange, 00948 double x) 00949 { double xadj = (x-x0)*oneOverXRange; 00950 assert(-NTraits<double>::getSignificant() <= xadj 00951 && xadj <= 1 + NTraits<double>::getSignificant()); 00952 clampInPlace(0.0,xadj,1.0); 00953 return yRange*oneOverXRange*dstepUp(xadj); } 00954 00958 inline double d2stepUp(double x) { 00959 assert(0 <= x && x <= 1); 00960 return 60*x*(1+x*(2*x-3)); //60x-180x^2+120x^3 00961 } 00962 00966 inline double d2stepDown(double x) {return -d2stepUp(x);} 00967 00971 inline double d2stepAny(double yRange, 00972 double x0, double oneOverXRange, 00973 double x) 00974 { double xadj = (x-x0)*oneOverXRange; 00975 assert(-NTraits<double>::getSignificant() <= xadj 00976 && xadj <= 1 + NTraits<double>::getSignificant()); 00977 clampInPlace(0.0,xadj,1.0); 00978 return yRange*square(oneOverXRange)*d2stepUp(xadj); } 00979 00983 inline double d3stepUp(double x) { 00984 assert(0 <= x && x <= 1); 00985 return 60+360*x*(x-1); //60-360*x+360*x^2 00986 } 00987 00991 inline double d3stepDown(double x) {return -d3stepUp(x);} 00992 00996 inline double d3stepAny(double yRange, 00997 double x0, double oneOverXRange, 00998 double x) 00999 { double xadj = (x-x0)*oneOverXRange; 01000 assert(-NTraits<double>::getSignificant() <= xadj 01001 && xadj <= 1 + NTraits<double>::getSignificant()); 01002 clampInPlace(0.0,xadj,1.0); 01003 return yRange*cube(oneOverXRange)*d3stepUp(xadj); } 01004 01005 // float 01006 01008 inline float stepUp(float x) 01009 { assert(0 <= x && x <= 1); 01010 return x*x*x*(10+x*(6*x-15)); } //10x^3-15x^4+6x^5 01012 inline float stepDown(float x) {return 1.0f-stepUp(x);} 01014 inline float stepAny(float y0, float yRange, 01015 float x0, float oneOverXRange, 01016 float x) 01017 { float xadj = (x-x0)*oneOverXRange; 01018 assert(-NTraits<float>::getSignificant() <= xadj 01019 && xadj <= 1 + NTraits<float>::getSignificant()); 01020 clampInPlace(0.0f,xadj,1.0f); 01021 return y0 + yRange*stepUp(xadj); } 01022 01024 inline float dstepUp(float x) 01025 { assert(0 <= x && x <= 1); 01026 const float xxm1=x*(x-1); 01027 return 30*xxm1*xxm1; } //30x^2-60x^3+30x^4 01029 inline float dstepDown(float x) {return -dstepUp(x);} 01031 inline float dstepAny(float yRange, 01032 float x0, float oneOverXRange, 01033 float x) 01034 { float xadj = (x-x0)*oneOverXRange; 01035 assert(-NTraits<float>::getSignificant() <= xadj 01036 && xadj <= 1 + NTraits<float>::getSignificant()); 01037 clampInPlace(0.0f,xadj,1.0f); 01038 return yRange*oneOverXRange*dstepUp(xadj); } 01039 01041 inline float d2stepUp(float x) 01042 { assert(0 <= x && x <= 1); 01043 return 60*x*(1+x*(2*x-3)); } //60x-180x^2+120x^3 01045 inline float d2stepDown(float x) {return -d2stepUp(x);} 01047 inline float d2stepAny(float yRange, 01048 float x0, float oneOverXRange, 01049 float x) 01050 { float xadj = (x-x0)*oneOverXRange; 01051 assert(-NTraits<float>::getSignificant() <= xadj 01052 && xadj <= 1 + NTraits<float>::getSignificant()); 01053 clampInPlace(0.0f,xadj,1.0f); 01054 return yRange*square(oneOverXRange)*d2stepUp(xadj); } 01055 01057 inline float d3stepUp(float x) 01058 { assert(0 <= x && x <= 1); 01059 return 60+360*x*(x-1); } //60-360*x+360*x^2 01061 inline float d3stepDown(float x) {return -d3stepUp(x);} 01063 inline float d3stepAny(float yRange, 01064 float x0, float oneOverXRange, 01065 float x) 01066 { float xadj = (x-x0)*oneOverXRange; 01067 assert(-NTraits<float>::getSignificant() <= xadj 01068 && xadj <= 1 + NTraits<float>::getSignificant()); 01069 clampInPlace(0.0f,xadj,1.0f); 01070 return yRange*cube(oneOverXRange)*d3stepUp(xadj); } 01071 01072 // long double 01073 01075 inline long double stepUp(long double x) 01076 { assert(0 <= x && x <= 1); 01077 return x*x*x*(10+x*(6*x-15)); } //10x^3-15x^4+6x^5 01079 inline long double stepDown(long double x) {return 1.0L-stepUp(x);} 01081 inline long double stepAny(long double y0, long double yRange, 01082 long double x0, long double oneOverXRange, 01083 long double x) 01084 { long double xadj = (x-x0)*oneOverXRange; 01085 assert(-NTraits<long double>::getSignificant() <= xadj 01086 && xadj <= 1 + NTraits<long double>::getSignificant()); 01087 clampInPlace(0.0L,xadj,1.0L); 01088 return y0 + yRange*stepUp(xadj); } 01089 01090 01092 inline long double dstepUp(long double x) 01093 { assert(0 <= x && x <= 1); 01094 const long double xxm1=x*(x-1); 01095 return 30*xxm1*xxm1; } //30x^2-60x^3+30x^4 01097 inline long double dstepDown(long double x) {return -dstepUp(x);} 01099 inline long double dstepAny(long double yRange, 01100 long double x0, long double oneOverXRange, 01101 long double x) 01102 { long double xadj = (x-x0)*oneOverXRange; 01103 assert(-NTraits<long double>::getSignificant() <= xadj 01104 && xadj <= 1 + NTraits<long double>::getSignificant()); 01105 clampInPlace(0.0L,xadj,1.0L); 01106 return yRange*oneOverXRange*dstepUp(xadj); } 01107 01109 inline long double d2stepUp(long double x) 01110 { assert(0 <= x && x <= 1); 01111 return 60*x*(1+x*(2*x-3)); } //60x-180x^2+120x^3 01113 inline long double d2stepDown(long double x) {return -d2stepUp(x);} 01115 inline long double d2stepAny(long double yRange, 01116 long double x0, long double oneOverXRange, 01117 long double x) 01118 { long double xadj = (x-x0)*oneOverXRange; 01119 assert(-NTraits<long double>::getSignificant() <= xadj 01120 && xadj <= 1 + NTraits<long double>::getSignificant()); 01121 clampInPlace(0.0L,xadj,1.0L); 01122 return yRange*square(oneOverXRange)*d2stepUp(xadj); } 01123 01124 01126 inline long double d3stepUp(long double x) 01127 { assert(0 <= x && x <= 1); 01128 return 60+360*x*(x-1); } //60-360*x+360*x^2 01130 inline long double d3stepDown(long double x) {return -d3stepUp(x);} 01132 inline long double d3stepAny(long double yRange, 01133 long double x0, long double oneOverXRange, 01134 long double x) 01135 { long double xadj = (x-x0)*oneOverXRange; 01136 assert(-NTraits<long double>::getSignificant() <= xadj 01137 && xadj <= 1 + NTraits<long double>::getSignificant()); 01138 clampInPlace(0.0L,xadj,1.0L); 01139 return yRange*cube(oneOverXRange)*d3stepUp(xadj); } 01140 01141 // int converts to double; only supplied for stepUp(), stepDown() 01144 inline double stepUp(int x) {return stepUp((double)x);} 01147 inline double stepDown(int x) {return stepDown((double)x);} 01148 01149 01208 // Doxygen should skip this helper template function 01210 template <class T> // float or double 01211 static inline std::pair<T,T> approxCompleteEllipticIntegralsKE_T(T m) { 01212 static const T a[] = 01213 { (T)1.38629436112, (T)0.09666344259, (T)0.03590092383, 01214 (T)0.03742563713, (T)0.01451196212 }; 01215 static const T b[] = 01216 { (T)0.5, (T)0.12498593597, (T)0.06880248576, 01217 (T)0.03328355346, (T)0.00441787012 }; 01218 static const T c[] = 01219 { (T)1, (T)0.44325141463, (T)0.06260601220, 01220 (T)0.04757383546, (T)0.01736506451 }; 01221 static const T d[] = 01222 { (T)0, (T)0.24998368310, (T)0.09200180037, 01223 (T)0.04069697526, (T)0.00526449639 }; 01224 01225 const T SignificantReal = NTraits<T>::getSignificant(); 01226 const T PiOver2 = NTraits<T>::getPi()/2; 01227 const T Infinity = NTraits<T>::getInfinity(); 01228 01229 SimTK_ERRCHK1_ALWAYS(-SignificantReal < m && m < 1+SignificantReal, 01230 "approxCompleteEllipticIntegralsKE()", 01231 "Argument m (%g) is outside the legal range [0,1].", (double)m); 01232 if (m >= 1) return std::make_pair(Infinity, (T)1); 01233 if (m <= 0) return std::make_pair(PiOver2, PiOver2); 01234 01235 const T m1=1-m, m2=m1*m1, m3=m1*m2, m4=m2*m2; // 4 flops 01236 const T lnm2 = std::log(m1); // ~50 flops 01237 01238 // The rest is 35 flops. 01239 const T K = (a[0] + a[1]*m1 + a[2]*m2 + a[3]*m3 + a[4]*m4) 01240 - lnm2*(b[0] + b[1]*m1 + b[2]*m2 + b[3]*m3 + b[4]*m4); 01241 const T E = (c[0] + c[1]*m1 + c[2]*m2 + c[3]*m3 + c[4]*m4) 01242 - lnm2*( d[1]*m1 + d[2]*m2 + d[3]*m3 + d[4]*m4); 01243 01244 return std::make_pair(K,E); 01245 } 01284 inline std::pair<double,double> 01285 approxCompleteEllipticIntegralsKE(double m) 01286 { return approxCompleteEllipticIntegralsKE_T<double>(m); } 01292 inline std::pair<float,float> 01293 approxCompleteEllipticIntegralsKE(float m) 01294 { return approxCompleteEllipticIntegralsKE_T<float>(m); } 01301 inline std::pair<double,double> 01302 approxCompleteEllipticIntegralsKE(int m) 01303 { return approxCompleteEllipticIntegralsKE_T<double>((double)m); } 01304 01305 // Doxygen should skip this template helper function 01307 template <class T> // float or double 01308 static inline std::pair<T,T> completeEllipticIntegralsKE_T(T m) { 01309 const T SignificantReal = NTraits<T>::getSignificant(); 01310 const T TenEps = 10*NTraits<T>::getEps(); 01311 const T Infinity = NTraits<T>::getInfinity(); 01312 const T PiOver2 = NTraits<T>::getPi() / 2; 01313 01314 // Allow a little slop in the argument since it may have resulted 01315 // from a numerical operation that gave 0 or 1 plus or minus 01316 // roundoff noise. 01317 SimTK_ERRCHK1_ALWAYS(-SignificantReal < m && m < 1+SignificantReal, 01318 "completeEllipticIntegralsKE()", 01319 "Argument m (%g) is outside the legal range [0,1].", (double)m); 01320 if (m >= 1) return std::make_pair(Infinity, (T)1); 01321 if (m <= 0) return std::make_pair(PiOver2, PiOver2); 01322 01323 const T k = std::sqrt(1-m); // ~25 flops 01324 T v1=1, w1=k, c1=1, d1=k*k; // initialize iteration 01325 do { // ~50 flops per iteration 01326 T v2 = (v1+w1)/2; 01327 T w2 = std::sqrt(v1*w1); 01328 T c2 = (c1+d1)/2; 01329 T d2 = (w1*c1+v1*d1)/(v1+w1); 01330 v1=v2; w1=w2; c1=c2; d1=d2; 01331 } while(std::abs(v1-w1) >= TenEps); 01332 01333 const T K = PiOver2/v1; // ~20 flops 01334 const T E = K*c1; 01335 01336 return std::make_pair(K,E); 01337 } 01364 inline std::pair<double,double> completeEllipticIntegralsKE(double m) 01365 { return completeEllipticIntegralsKE_T<double>(m); } 01373 inline std::pair<float,float> completeEllipticIntegralsKE(float m) 01374 { return completeEllipticIntegralsKE_T<float>(m); } 01381 inline std::pair<double,double> completeEllipticIntegralsKE(int m) 01382 { return completeEllipticIntegralsKE_T<double>((double)m); } 01383 01386 } // namespace SimTK 01387 01388 #endif //SimTK_SIMMATRIX_SCALAR_H_