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