> [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