> [snip]
>
> I've been looking into an earlier version of the proposed math constants
> before and asked myself how to implement a generic function like
>
> template<class T>
> T circle_area (const T &radius) {
>     return math_constants<T>::pi * radius * radius;
> }
>
> How should this be done?
>
> Thanks,
>
> Joerg

Attached is an example using Michael Kenniston's Kunning Function constants.

Briefly

template <typename T>
T circle_area(const T& radius)
{
  // Usage example: circle_area<double>( 2.) // Explicit type double.
  // or             circle_area(2.F) // Implicit type float.
        return boost::math::constant< T, boost::math::pi_tag >() * radius * radius;
}

It compiles with MSVC 7.0 (but not 6 - see MK's original example for why not).
(long double == double for MSVC, so long double not fully testable/useful).

It seems to do the trick, without too many surprises.  I have displayed the
output using the 17 significant digits for double so one can see the difference
between a float pi 3.1415927410125732 and a double pi 3.1415926535897931 (even
though only 9 are really significant for float).

        cout << "circle_area<float>(1.) = "  << circle_area<float>(1.) << endl; //
Explicit type float.
        cout << "circle_area<double>(1.) = "  << circle_area<double>(1.) << endl; //
Explicit type double.
        cout << "circle_area(1.F) = "  << circle_area(1.F) << endl; // Implicit type
float.
        cout << "circle_area(1.) = "  << circle_area(1.) << endl; // Implicit type
double.
        cout << "circle_area(1.L) = "  << circle_area(1.L) << endl; // implicit type
long double.
        cout << "circle_area<double>(1.F) = "  << circle_area<double>(1.F) << endl; //
Explicit over-rides implicit.

And silly types like int fail helpfully.
  // cout << "circle_area(1) = "  << circle_area(1)<< endl; // Implicit int -
does not link!
  // cout << "circle_area<int>(1.) = "  << circle_area<int>(1.)<< endl; //
Explicit int - does not compile!

Output is

Test test_circle_area.cpp Thu Jan 23 00:06:28 2003
float pi  = 3.14159274
double pi = 3.1415926535897931
float pi  = 3.1415927410125732
circle_area<float>(1.) = 3.1415927410125732
circle_area<double>(1.) = 3.1415926535897931
circle_area(1.F) = 3.1415927410125732
circle_area(1.) = 3.1415926535897931
circle_area(1.L) = 3.1415926535897931
circle_area<double>(1.F) = 3.1415926535897931
circle_area<long double>(1.) = 3.1415926535897931
circle_area<float>(2.) = 12.566370964050293
circle_area<double>(2.) = 12.566370614359172
circle_area(2.F) = 12.566370964050293
circle_area(2.) = 12.566370614359172
circle_area(2.L) = 12.566370614359172
circle_area<double>(2.F) = 12.566370614359172
boost::math::constant< float, boost::math::pi_tag >() 3.1415927410125732

I haven't looked at any assembler to check on efficiency, but believe/hope from
previous examples that it will be optimal if inlined.

Does this look sensible/useful?

Paul

Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB  UK
+44 1539 561830   Mobile +44 7714 33 02 04
Mobile mailto:[EMAIL PROTECTED]
mailto:[EMAIL PROTECTED]
<?xml version="1.0" encoding = "Windows-1252"?>
<VisualStudioProject
        ProjectType="Visual C++"
        Version="7.00"
        Name="Generic_function"
        ProjectGUID="{641D5868-A2BA-47DE-9E36-1E28928FADEA}"
        Keyword="Win32Proj">
        <Platforms>
                <Platform
                        Name="Win32"/>
        </Platforms>
        <Configurations>
                <Configuration
                        Name="Debug|Win32"
                        OutputDirectory="Debug"
                        IntermediateDirectory="Debug"
                        ConfigurationType="1"
                        CharacterSet="2">
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
                                PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
                                MinimalRebuild="TRUE"
                                BasicRuntimeChecks="3"
                                RuntimeLibrary="5"
                                UsePrecompiledHeader="0"
                                WarningLevel="3"
                                Detect64BitPortabilityProblems="TRUE"
                                DebugInformationFormat="4"/>
                        <Tool
                                Name="VCCustomBuildTool"/>
                        <Tool
                                Name="VCLinkerTool"
                                OutputFile="$(OutDir)/Generic_function.exe"
                                LinkIncremental="2"
                                GenerateDebugInformation="TRUE"
                                ProgramDatabaseFile="$(OutDir)/Generic_function.pdb"
                                SubSystem="1"
                                TargetMachine="1"/>
                        <Tool
                                Name="VCMIDLTool"/>
                        <Tool
                                Name="VCPostBuildEventTool"/>
                        <Tool
                                Name="VCPreBuildEventTool"/>
                        <Tool
                                Name="VCPreLinkEventTool"/>
                        <Tool
                                Name="VCResourceCompilerTool"/>
                        <Tool
                                Name="VCWebServiceProxyGeneratorTool"/>
                        <Tool
                                Name="VCWebDeploymentTool"/>
                </Configuration>
                <Configuration
                        Name="Release|Win32"
                        OutputDirectory="Release"
                        IntermediateDirectory="Release"
                        ConfigurationType="1"
                        CharacterSet="2">
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="2"
                                InlineFunctionExpansion="1"
                                OmitFramePointers="TRUE"
                                PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
                                StringPooling="TRUE"
                                RuntimeLibrary="4"
                                EnableFunctionLevelLinking="TRUE"
                                UsePrecompiledHeader="0"
                                WarningLevel="3"
                                Detect64BitPortabilityProblems="TRUE"
                                DebugInformationFormat="3"/>
                        <Tool
                                Name="VCCustomBuildTool"/>
                        <Tool
                                Name="VCLinkerTool"
                                OutputFile="$(OutDir)/Generic_function.exe"
                                LinkIncremental="1"
                                GenerateDebugInformation="TRUE"
                                SubSystem="1"
                                OptimizeReferences="2"
                                EnableCOMDATFolding="2"
                                TargetMachine="1"/>
                        <Tool
                                Name="VCMIDLTool"/>
                        <Tool
                                Name="VCPostBuildEventTool"/>
                        <Tool
                                Name="VCPreBuildEventTool"/>
                        <Tool
                                Name="VCPreLinkEventTool"/>
                        <Tool
                                Name="VCResourceCompilerTool"/>
                        <Tool
                                Name="VCWebServiceProxyGeneratorTool"/>
                        <Tool
                                Name="VCWebDeploymentTool"/>
                </Configuration>
        </Configurations>
        <Files>
                <Filter
                        Name="Source Files"
                        Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
                        <File
                                RelativePath="test_circle_area.cpp">
                        </File>
                </Filter>
                <Filter
                        Name="Header Files"
                        Filter="h;hpp;hxx;hm;inl;inc">
                        <File
                                RelativePath="function_constants.hpp">
                        </File>
                </Filter>
                <Filter
                        Name="Resource Files"
                        Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
                </Filter>
        </Files>
        <Globals>
        </Globals>
</VisualStudioProject>
#ifndef HPP_FUNCTION_CONSTANTS
#define HPP_FUNCTION_CONSTANTS

// Based on a post by Michael Kenniston:  
http://groups.yahoo.com/group/boost/message/14867
// Written by J:\Cpp\WinNTL-5_0c\NTL5\makeConstants\makeConstants.cpp Tue Oct 16 
15:40:55 2001
// Version 1.1
// Using Victor Shoup's NTL version 5.0c (www.shoup.net/ntl)

// Copyright Paul A Bristow, hetp Chromatography, 2002
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" with express or implied warranty,
// and with no claim as to its suitability for any purpose.

// C++ floating-point types accurate to 40 decimal digits.

// For documentation and sources see math_constants.htm

// This file is a collection of some basic mathematical constants.

// The objective is to achieve the full accuracy possible
// with IEC559/IEEE745 Floating point hardware and C++ language.
// This has no extra cost to the user, but reduces irritating effects
// caused by the inevitable limitations of floating point calculations.
// At least these manifest as spurious least significant digits,
// at worst algorithms that fail because comparisons fail.
// 40 decimal places ensures no loss of accuracy
// even for 128-bit significand floating-point.

namespace boost
{
  namespace math
        { // Sub-space for math - provisional.
                template< typename Representation, typename Tag >
                struct constant
                { // The "constant" class/struct provides a place to put
      // the actual definition of the value of each constant.
                        // It also turns an implicit conversion operation
                        // (which does not need any parentheses) into an explicit call 
to the
                        // correct function that actually knows (and returns) the 
right value.
                        public:
                        // constant(){} // Unclear if this constructor is required or 
not.
                        // Avoid contructor here (if compiler and options allow)
                        // to prevent unused constants creating unwanted constructor.
                        // Not all compilers and/or linkers optimise these out.
                        operator Representation() const;
                        // operator () returns the value of the constant.
      // Fully specialized for each Representation and Tag pair.
                        // Representation may be:
                        //   operator float() const,
                        //   operator double() const, or
                        //   operator long double () const,
                        // or other user-defined floating-point type.
                }; // template< typename Representation, typename Tag > class constant

                struct pi_tag {}; // Identifies constant as pi.

                // Specializations for three builtin floating-point types:
                // Note correct suffix F or L is required.
                template<> inline constant< float, pi_tag >::operator float() const
                { 
                        return 3.141592653589793238462643383279502884197F;
                }
                
                template<> inline constant< double, pi_tag >::operator double() const
                {
                        return 3.141592653589793238462643383279502884197;
                }
                
                template<> inline constant< long double, pi_tag >::operator long 
double() const
                {
                        return 3.141592653589793238462643383279502884197L;
                }
                // Could add specializations for other representations.

                
                // constant::constant< double, pi_tag >() {} // requires argument list.
                // so not used.

                // Define constant is namespaces to hold three builtin floating-point 
representations.
                namespace float_constants
                {
                        constant< float, pi_tag > const pi;
                }               
                namespace double_constants
                {
                        constant< double, pi_tag > const pi;
                }
                namespace long_double_constants
                {
                        constant< long double, pi_tag > const pi;
                }
                // Could add other namespace(s) for user defined representation(s). 

  } // namespace math
} // namespace boost

// Similarly for other constants.

namespace boost
{
  namespace math
  {
    // sqrt2
                struct sqrt2_tag {}; // Identifies constant as sqrt2.

    template<> inline constant<float, sqrt2_tag >::operator float() const
    {
      return 1.41421356237309504880168872420969807857F;
    } 
    template<> inline constant< double, sqrt2_tag>::operator double() const
    {
      return 1.41421356237309504880168872420969807857;
    }
    template<> inline constant< long double, sqrt2_tag >::operator long double() const
    {
      return 1.41421356237309504880168872420969807857L;
    }

    namespace float_constants
    {
      constant<float, sqrt2_tag > const sqrt2;
    }
    namespace double_constants
    {
      constant<double, sqrt2_tag > const sqrt2; 
    }
    namespace long_double_constants
    {
      constant<long double, sqrt2_tag > const sqrt2;
    }

                // e
    struct e_tag {};
    template<> inline constant< long double, e_tag>::operator long double() const
    {
      return 2.7182818284590452353602874713526624977572L;
    }
    template<> inline constant<double, e_tag >::operator double() const
    {
      return 2.7182818284590452353602874713526624977572;
    }
    template<> inline constant<float, e_tag >::operator float() const
    {
      return 2.7182818284590452353602874713526624977572F;
    } 

    namespace float_constants
    {
      constant<float, e_tag > const e;
    }
    namespace double_constants
    {
      constant<double, e_tag > const e; 
    }
    namespace long_double_constants
    {
      constant< long double, e_tag> const e;
    }
  }// namespace math
} // namespace boost

/*

*/

#endif
// End of function_constants.hpp 
// test_circle_area.cpp

// (C) Copyright Paul A Bristow, hetp Chromatography, 2003
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" with express or implied warranty,
// and with no claim as to its suitability for any purpose.

#include <iostream>
#include <limits> // for numeric_limits

#include "function_constants.hpp"

using std::cout;
using std::endl;

const char nl = '\n';
const char tab = '\t';
const char space = ' ';

// Question posed by Joerg Walter, 22 Jan 2003 22:14

template <typename T>
T circle_area(const T& radius)
{
  // Usage example:   circle_area<double>( 2.)
  // or   circle_area(2.F)
        return boost::math::constant< T, boost::math::pi_tag >() * radius * radius;
}

int main()
{
        cout << "Test " << __FILE__ << ' ' << __TIMESTAMP__ << endl;
        
        // Calculate number of significant digits, strictly
        // ceil(1 + std::numeric_limits<float>::digits*log10(2.))
        // but need an approximation that does not use floating-point
        // to compute correctly at compile time.
        int float_significand_digits =  std::numeric_limits<float>::digits; // 24 bits
        int float_significant_digits =  2 + float_significand_digits * 30101/100000;
        int double_significand_digits =  std::numeric_limits<double>::digits; // 53 
bits
        int double_significant_digits =  2 + double_significand_digits * 30101/100000; 
// 53 bits for MSVC
        cout.precision(double_significant_digits);// Ensure they are all output.

        // This is needed to show the difference between pi float and double
        // (and long double if not MSVC).

        // Or for using float and double constants at the same time,
        // users can explicitly access fully specified constants at any time:
        cout.precision(float_significant_digits);
        // Ensure all float significant (9) digits are displayed.
        cout << "float pi = " << boost::math::float_constants::pi << "\n"; //  
3.14159274
        cout.precision(double_significant_digits);
        cout << "double pi = " << boost::math::double_constants::pi << "\n"; // 
3.1415926535897931
        cout << "float pi = " << boost::math::float_constants::pi << "\n"; // 
double_sig_digits 3.1415927410125732

        cout << "circle_area<float>(1.) = "  << circle_area<float>(1.) << endl; // 
Explicit type float.
        cout << "circle_area<double>(1.) = "  << circle_area<double>(1.) << endl; // 
Explicit type 
        cout << "circle_area(1.F) = "  << circle_area(1.F) << endl; // Implicit type 
float.
        cout << "circle_area(1.) = "  << circle_area(1.) << endl; // Implicit type 
double.
        cout << "circle_area(1.L) = "  << circle_area(1.L) << endl; // implicit type 
long double.
        cout << "circle_area<double>(1.F) = "  << circle_area<double>(1.F) << endl; // 
Explicit over-rides implicit.
        cout << "circle_area<long double>(1.) = "  << circle_area<long double>(1.)<< 
endl; // same as double for MSVC.
  // cout << "circle_area(1) = "  << circle_area(1)<< endl; // Implicit int - does not 
link!
  // cout << "circle_area<int>(1.) = "  << circle_area<int>(1.)<< endl; // Explicit 
int - does not compile!

        cout << "circle_area<float>(2.) = "  << circle_area<float>(2.) << endl; // 
Explicit type float.
        cout << "circle_area<double>(2.) = "  << circle_area<double>(2.) << endl; // 
Explicit type 
        cout << "circle_area(2.F) = "  << circle_area(2.F) << endl; // Implicit type 
float.
        cout << "circle_area(2.) = "  << circle_area(2.) << endl; // Implicit type 
double.
        cout << "circle_area(2.L) = "  << circle_area(2.L) << endl; // implicit type 
long double.
        cout << "circle_area<double>(2.F) = "  << circle_area<double>(2.F) << endl; // 
Explicit over-rides implicit.

        float pi_f = boost::math::constant< float, boost::math::pi_tag >();
        cout << "boost::math::constant< float, boost::math::pi_tag >() " << pi_f << 
endl;

        return 0;
} // int main()



/*

Output is

Test test_circle_area.cpp Thu Jan 23 00:06:28 2003
float pi = 3.14159274
double pi = 3.1415926535897931
float pi = 3.1415927410125732
circle_area<float>(1.) = 3.1415927410125732
circle_area<double>(1.) = 3.1415926535897931
circle_area(1.F) = 3.1415927410125732
circle_area(1.) = 3.1415926535897931
circle_area(1.L) = 3.1415926535897931
circle_area<double>(1.F) = 3.1415926535897931
circle_area<long double>(1.) = 3.1415926535897931
circle_area<float>(2.) = 12.566370964050293
circle_area<double>(2.) = 12.566370614359172
circle_area(2.F) = 12.566370964050293
circle_area(2.) = 12.566370614359172
circle_area(2.L) = 12.566370614359172
circle_area<double>(2.F) = 12.566370614359172
boost::math::constant< float, boost::math::pi_tag >() 3.1415927410125732
Press any key to continue


*/
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Reply via email to