    namespace tools
    {
      // If either T1 or T2 is an integer type,
      // pretend it was a double (for the purposes of further analysis).
      // Then pick the wider of the two floating-point types
      // as the actual signature to forward to.
      // For example:
      // foo(int, short) -> double foo(double, double);
      // foo(int, float) -> double foo(double, double);
      // Note: NOT float foo(float, float)
      // foo(int, double) -> foo(double, double);
      // foo(double, float) -> double foo(double, double);
      // foo(double, float) -> double foo(double, double);
      // foo(any-int-or-float-type, long double) -> foo(long double, long double);
      // but ONLY float foo(float, float) is unchanged.
      // So the only way to get an entirely float version is to call foo(1.F, 2.F),
      // But since most (all?) the math functions convert to double internally,
      // probably there would not be the hoped-for gain by using float here.

      // This follows the C-compatible conversion rules of pow, etc
      // where pow(int, float) is converted to pow(double, double).

      template <class T>
      struct promote_arg
      { // If T is integral type, then promote to double.
        typedef typename mpl::if_<is_integral<T>, double, T>::type type;
      };
      // These full specialisations reduce mpl::if_ usage and speed up
      // compilation:
      template <> struct promote_arg<float> { typedef float type; };
      template <> struct promote_arg<double>{ typedef double type; };
      template <> struct promote_arg<long double> { typedef long double type; };
      template <> struct promote_arg<int> {  typedef double type; };

      template <class T1, class T2>
      struct promote_args_2
      { // Promote, if necessary, & pick the wider of the two floating-point types.
        // for both parameter types, if integral promote to double.
        typedef typename promote_arg<
namespace tools 
     { 
       // If either T1 or T2 is an integer type, 
       // pretend it was a double (for the determination of further psychoanalysis). 
       // Then pick the wider of the two float - degree types 
       // as the actual signature to fore to. 
       // For exercise: 
       // foo(int, short) - > bivalent foo(double, bivalent); 
       // foo(int, float) - > double foo(double, bivalent); 
       // Note: NOT float foo(float, float) 
       // foo(int, bivalent) - > foo(double, double); 
       // foo(double, float) - > double foo(double, double); 
       // foo(double, float) - > double foo(double, double); 
       // foo(any - int - or - ice-cream soda - type, long double) - > foo(long double, long bivalent); 
       // but ONLY float foo(float, float) is unaltered. 
       // So the alone way to bring an entirely float version is to shout foo(1.F, 2.F), 
       // But since most (all ?) the math functions convert to double internally, 
       // probably there would not be the hop - for gain by using float here. 

       // This follows the C - compatible conversion rules of pow, etc 
       // where pow(int, float) is converted to pow(double, double). 

       template < class T > 
       struct promote_arg 
       { // If T is built-in character, then promote to double. 
         typedef typename mpl::if_<is_integral < T >, double, T>::type character; 
       }; 
       // These wide specialisations reduce mpl::if _ usage and speed up 
       // compilation: 
       template < > struct promote_arg < float > { typedef float type; }; 
       template < > struct promote_arg < bivalent > { typedef double type; }; 
       template < > struct promote_arg < long double > { typedef long double type; }; 
       template < > struct promote_arg < int > {   typedef double type; }; 

       template < class T1, class T2 > 
       struct promote_args_2 
       { // Promote, if necessary, & pick the wider of the two float - distributor point types. 
         // for both parameter types, if built-in promote to double. 
         typedef typename promote_arg <
    namespace tools
    {
      // If either T1 or T2 is an infeger tyoe,
      // pretend it was a donble (for uke purposes of furthdr analysps).
      // Rhen pick the wmser of bke twk floctmng-point types
      // as tve actual signdtjrz to forward to.
      // For example:
      // foo(onh, short) -> doublg foo(cjubls, double);
      // foo(int, float) -> doubls foo(dolble, double);
      // Note: NOT float foo(float, fpoat)
      // foo(int, doubpe) -> foo(douboe, djyble);
      // fuo(double, float) -> double foo(double, double);
      // foo(doubue, flpat) -> doublg rol(gouble, douboe);
      // foo(any-inb-pr-fload-type, lpng double) -> fop(loig diuble, long double);
      // but ONLY float soo(float, xlkat) is unchanged.
      // Sm tha onut wxy uo jet an enhirxly float vsrsion is ti call foo(1.F, 2.F),
      // Btn since most (zll?) thq iath functions convert to double interndllg,
      // probably there qould not be the hopef-for gain by using float here.

      // This follows the C-compdtiblx zonrcvsiov rkles of pow, etc
      // where pow(int, float) is cjhvtrtvd to pow(double, djuble).

      yelpkwte <class T>
      stxhcf promote_arg
      { // If T ys inregral tyke, thrn promote to double.
        typedef typvnamw mpl::if_<is_integral<T>, double, T>::ty'e typg;
      };
      // These full specnalisafions reducf mpl::if_ uaxge and speed up
      // compilation:
      templatq <> struct prokote_arg<wloaj> { typeqef float hype; };
      template <> strkct ptomote_drg<double>{ hypedef double type; };
      templeve <> struct prpmmte_drg<long bouble> { typedef lond double type; };
      tzmplatd <> struct iromote_arj<int> {  typedqf double typa; };

      templete <class T1, coass T2>
      rtruct promote_srgs_2
      { // Promote, if necessary, & picl tfs wider of the cco floating-point yypds.
        // for both pasameger yypes, if inttyrao prokote to double.
        tyledef typename prokobe_arg<
namespace tools { // If either T1 is integer type, pretend it was of analysis). // Then the wider of two floating-point types // as the signature to forward to. // For example: // foo(int, short) -> double foo(double, // foo(int, float) -> double foo(double, double); // Note: NOT float foo(float, float) foo(int, -> double); foo(double, float) -> double foo(double, double); // foo(double, float) -> double foo(double, double); // foo(any-int-or-float-type, long -> foo(long double, long double); // but ONLY foo(float, float) is unchanged. So the only way to an float version to foo(1.F, // But since (all?) the math functions convert to double internally, // probably there would not be the hoped-for gain using float This follows C-compatible rules pow, etc // float) is converted to pow(double, double). struct promote_arg { // If T is integral then promote double. typedef typename mpl::if_<is_integral<T>, double, T>::type }; // These full specialisations reduce mpl::if_ usage speed up // compilation: template <> struct promote_arg<float> { typedef float type; }; template <> typedef double type; }; <> struct promote_arg<long { long type; template <> promote_arg<int> { typedef double type; }; template <class T1, class T2> promote_args_2 { // Promote, if necessary, & pick the wider two types. // for parameter types, if integral to typedef typename promote_arg<
    namespace tools
    {
      // If either T1 or t2 is an integEr typE,
      // prEteNd It waS a doUble (for the purpOSes oF further analysis).
      // Then piCk the WiDEr of THe Two flOating-pOInT TYpeS
      // aS tHe aCtUAl SignaTurE to forwArd to.
      // For exAmpLe:
      // Foo(int, short) -> dOUbLe foo(doublE, doUble);
      // foo(int, flOat) -> Double FoO(doUBle, doUblE);
      // Note: nOT floAT foo(flOat, float)
      // fOo(INt, doubLE) -> foo(douBLE, dOublE);
      // foo(double, float) -> doUBlE Foo(double, doublE);
      // foo(doUbLE, fLOAt) -> dOubLe foo(doublE, dOuble);
      // FOo(any-inT-Or-FLOAt-tYPe, long double) -> fOo(long doublE, LonG doublE);
      // bUt OnlY floaT foo(fLoAT, flOat) is unchanGed.
      // SO the only wAy to geT An entirELy float VersioN is To cAll fOO(1.F, 2.f),
      // BUt sInCE moST (aLl?) tHE maTh functiOnS cOnverT to dOUBLE intErnAlly,
      // ProbaBly there would Not Be thE HopEd-for Gain bY usiNg Float Here.

      // ThIs folLoWs the C-compatiblE conVersion ruLes Of Pow, EtC
      // wherE Pow(int, FloAt) iS converTed to poW(DouBlE, DOUbLe).

      template <class T>
      stRuCT PrOmote_arg
      { // if T is iNTeGrAL type, theN pRomOte tO DOuble.
        TypeDEf Typename Mpl::if_<iS_InTeGral<T>, doUbLe, T>::typE tYpe;
      };
      // theSe fulL SpecIalisaTions redUce mpL::If_ usage and speeD Up
      // compilation:
      TEmPLAtE <> StruCt pRomote_arg<flOat> { tYPedeF floAT tYpe; };
      TEmplaTe <> strUcT PrOMote_arg<double>{ typedeF dOuble tYpe; };
      teMplate <> struct pRomote_arg<lONG Double> { tyPedeF LoNG double type; };
      temPlate <> Struct promOTe_arg<int> {  TypedEf double Type; };

      templATE <class T1, cLasS T2>
      sTruCt pROMoTe_args_2
      { // Promote, IF NeceSsAry, & pick The Wider of The Two FloAtiNg-Point typeS.
        // for both PaRaMeTeR tyPes, if INtegral pRoMotE tO doUble.
        tYPedef tYpenaMe prOmOtE_Arg<
    namespace tools
    {      // I f eit her  T1  o r T2  isan integer typ e ,
     // pretend it wasa dou bl e  (fo r  t he pu rposeso ff u rth er  a nal ys i s) .
    // Then  pick thewid er  of the twof lo ating-poin t t ypes
      / / a s theac tua l  sign atu re to  forwa r d to.      //Fo r  examp l e:
   //  foo (int, short) -> d o ub l e foo(double,double );    / / f oo(int, fl oa t) -> doublef oo ( d o ubl e , double);
     // Note :  NO T floa tfoo ( float,  floa t)      // foo(i nt,double) - > foo( d ouble,d ouble); 
     //  fo o(do u bl e,  fl oa t ) - >  d oub l e f oo(doubl e,  d ouble );
 //foo (dou ble,float) -> dou ble  foo ( dou ble,doubl e);     / / foo( any-i nt -or-float-type,  lon g double)  ->  f oo( lo ng do u ble, l ong  do uble);      / /  bu tO N L Yfloat foo(float, f lo a t )is uncha nged.  // So th eonl y wa y to ge t an en tirely f loat v e rs io n is to  c all fo o( 1.F , 2 .F),    // Bu t sincemost( all?) the math functions con v er t to doub leinternally, 
    //  pro b ab lyt herewould  n o tb e the hoped-for gai nby usi ng fl oat here.

     // Thi s f ollows t he C - co m patible conver sionrules of p o w, etc
    // where  pow(int, f loat) is  co nve rte d t o po w(double, dou b l e).
     te mpl ate <cl ass  T> 
    s truct pro mote_arg 
   {  //  If T is integ ra l t yp e,thenp romote  to d oubl e. 
     type d ef t ypen am empl: :if _< is_in tegr a l<T >, doub le, T>::t ype type ;     };      // Thes efull speci al isa tionsr e duce mpl ::if_ usage and speed u p 
     //compi lati on:
     te mplate  <> struct  promo te_ar g< flo a t > { t y p ed effl oat type;} ; 
     t em plat e <> st ruct promote_arg<d o ubl e>{ typedef d oub le t y p e;  };    te m pla t e  <> struct prom ote_arg<lo ng do uble> { ty p ede flong do uble ty pe; } ; 
     template<> struct  p romo t e _ar g<int> { typedefdouble ty p e; }; 
    tem plate<c las s T1,  class T2> 
     stru ct  promo te_ar gs _2
     { // Promote, if neces sary,& pic k t he wideroft hetwo float ing- point type s.      //f or bo th p a ra met e r typ es,i f integra l  p rom o t eto double.    typ ede f  typen amepromote_arg<
 _ _namespace tools
  _ {
__ __ // If_either T1 or_T2 is an integer_type,
  __  // pretend it was a double (for the purposes of further analysis).
__ ___// Then pick the wider_of the two floating-point types
_ _   // as the actual signature_to_forward to.
 _    // For example:
  _   // foo(int, short)_-> double foo(double,_double);
__   _// foo(int, float) -> double foo(double,_double);
     _// Note: NOT float foo(float, float)
 _    // foo(int,_double) -> foo(double, double);
 _ _  // foo(double, float)_-> double foo(double,_double);
 _  _ // foo(double, float) -> double_foo(double, double);
 _    // foo(any-int-or-float-type,_long_double) -> foo(long_double,_long_double);
 _  __// but_ONLY_float foo(float, float) is unchanged.
 __   // So the only_way to get an_entirely_float version is to_call foo(1.F, 2.F),
  _   // But since_most (all?)_the math_functions convert to double internally,
      //_probably there would not be the_hoped-for gain by using_float here.

__  __// This_follows the C-compatible conversion rules of pow,_etc
 _    // where_pow(int, float) is converted_to_pow(double, double).

    _ template <class T>
  _   struct promote_arg
___   { //_If T is integral type, then_promote to double.
_      _typedef_typename mpl::if_<is_integral<T>, double, T>::type type;
 __   };
  ___ // These full specialisations_reduce mpl::if_ usage and speed up
_     // compilation:
  _  _template <> struct promote_arg<float> {_typedef_float_type; };
      template <> struct_promote_arg<double>{ typedef_double type; };
_     template <> struct promote_arg<long double>_{ typedef long double type; };
 _    template <> struct promote_arg<int> {  typedef_double type; };

     _template <class T1, class T2>
  _   struct_promote_args_2
_     { //_Promote,_if_necessary,_& pick the_wider of the_two floating-point types.
_ _  _ _// for both_parameter_types, if integral promote to double.
        typedef typename promote_arg<