Vin*_*ent 17 c++ floating-point c++-standard-library c++11
C++ 2011标准库的nextafter和nexttoward函数有什么区别?
Xeo*_*Xeo 15
由于函数源自C,因此它们不能被重载,这意味着对于执行相同但具有不同参数(-type)s的函数有两个不同的名称.以下是原始签名:
float nextafter(float, float);
float nexttoward(float, long double);
Run Code Online (Sandbox Code Playgroud)
现在标准只是说应该有一些重载使C++(§26.8 [c.math] p11)中的东西变得更好:
此外,还应有足够的额外过载来确保:
- 如果对应于
double参数的任何参数具有类型,long double,则对应于double参数的所有参数都被有效地转换为long double.- 否则,如果对应于
double参数的任何参数具有类型double或整数类型,则对应于double参数的所有参数都被有效地转换为double.- 否则,所有与参数对应的
double参数都被有效地转换为float.另见:ISO C 7.5,7.10.2,7.10.6.
与其他答案不明显的一个关键区别是返回类型。对于nextafter,返回类型是from和to类型的 std::common_type 。对于nexttoward,返回类型是fromtype ;由于to提升为 long double,因此其类型并不重要。一些测试代码具有指导意义。
输出:
nextafter ( from, to ) vs.
nexttoward( from, to )
float s = 1.401e-45
double d = 4.941e-324
long double q = 3.645e-4951
----- `from` is float
nextafter ( 0.0f, s ) = 1.401e-45 float
nexttoward( 0.0f, s ) = 1.401e-45 float
nextafter ( 0.0f, d ) = 4.941e-324 double
nexttoward( 0.0f, d ) = 1.401e-45 float
nextafter ( 0.0f, q ) = 3.645e-4951 long double
nexttoward( 0.0f, q ) = 1.401e-45 float
----- `from` is double
nextafter ( 0.0, s ) = 4.941e-324 double
nexttoward( 0.0, s ) = 4.941e-324 double
nextafter ( 0.0, d ) = 4.941e-324 double
nexttoward( 0.0, d ) = 4.941e-324 double
nextafter ( 0.0, q ) = 3.645e-4951 long double
nexttoward( 0.0, q ) = 4.941e-324 double
----- `from` is long double
nextafter ( 0.0L, s ) = 3.645e-4951 long double
nexttoward( 0.0L, s ) = 3.645e-4951 long double
nextafter ( 0.0L, d ) = 3.645e-4951 long double
nexttoward( 0.0L, d ) = 3.645e-4951 long double
nextafter ( 0.0L, q ) = 3.645e-4951 long double
nexttoward( 0.0L, q ) = 3.645e-4951 long double
Run Code Online (Sandbox Code Playgroud)
代码:
// Test nextafter and nextforward.
// nextafter's return type is std::common_type( from, to ).
// nexttoward's return type is same as `from`;
// `to` is promoted to long double, which doesn't really have any external effect.
#include <cmath>
#include <iomanip>
#include <iostream>
//------------------------------------------------------------------------------
// For type(), see
// /sf/ask/5730931/
#include <type_traits>
#include <typeinfo>
#include <memory>
#include <string>
#include <cstdlib>
// for demangling on non-Microsoft platforms
#ifndef _MSC_VER
#include <cxxabi.h>
#endif
template <typename T>
std::string type()
{
using TR = typename std::remove_reference<T>::type;
std::unique_ptr< char, void(*)(void*) > own(
#ifndef _MSC_VER
abi::__cxa_demangle( typeid(TR).name(), nullptr, nullptr, nullptr ),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
template <typename T>
std::string type( T x )
{
return type<T>();
}
//------------------------------------------------------------------------------
int main( int argc, char** argv )
{
std::cout << std::setprecision( 4 );
std::cout << "nextafter ( from, to ) vs.\n"
<< "nexttoward( from, to )\n\n";
float s = std::nextafter( 0.0f, 1.0f );
double d = std::nextafter( 0.0, 1.0 );
long double q = std::nextafter( 0.0L, 1.0L );
std::cout << "float s = " << s << '\n';
std::cout << "double d = " << d << '\n';
std::cout << "long double q = " << q << "\n\n";
std::cout << "----- `from` is float\n"; // Result type
auto x1 = std::nextafter ( 0.0f, s ); // float
auto y1 = std::nexttoward( 0.0f, s ); // float
std::cout << "nextafter ( 0.0f, s ) = " << x1 << " " << type( x1 ) << '\n';
std::cout << "nexttoward( 0.0f, s ) = " << y1 << " " << type( y1 ) << "\n\n";
auto x2 = std::nextafter ( 0.0f, d ); // double
auto y2 = std::nexttoward( 0.0f, d ); // float
std::cout << "nextafter ( 0.0f, d ) = " << x2 << " " << type( x2 ) << '\n';
std::cout << "nexttoward( 0.0f, d ) = " << y2 << " " << type( y2 ) << "\n\n";
auto x3 = std::nextafter ( 0.0f, q ); // long double
auto y3 = std::nexttoward( 0.0f, q ); // float
std::cout << "nextafter ( 0.0f, q ) = " << x3 << " " << type( x3 ) << '\n';
std::cout << "nexttoward( 0.0f, q ) = " << y3 << " " << type( y3 ) << "\n\n";
std::cout << "----- `from` is double\n";
auto x4 = std::nextafter ( 0.0, s ); // double
auto y4 = std::nexttoward( 0.0, s ); // double
std::cout << "nextafter ( 0.0, s ) = " << x4 << " " << type( x4 ) << '\n';
std::cout << "nexttoward( 0.0, s ) = " << y4 << " " << type( y4 ) << "\n\n";
auto x5 = std::nextafter ( 0.0, d ); // double
auto y5 = std::nexttoward( 0.0, d ); // double
std::cout << "nextafter ( 0.0, d ) = " << x5 << " " << type( x5 ) << '\n';
std::cout << "nexttoward( 0.0, d ) = " << y5 << " " << type( y5 ) << "\n\n";
auto x6 = std::nextafter ( 0.0, q ); // long double
auto y6 = std::nexttoward( 0.0, q ); // double
std::cout << "nextafter ( 0.0, q ) = " << x6 << " " << type( x6 ) << '\n';
std::cout << "nexttoward( 0.0, q ) = " << y6 << " " << type( y6 ) << "\n\n";
std::cout << "----- `from` is long double\n";
auto x7 = std::nextafter ( 0.0L, s ); // long double
auto y7 = std::nexttoward( 0.0L, s ); // long double
std::cout << "nextafter ( 0.0L, s ) = " << x7 << " " << type( x7 ) << '\n';
std::cout << "nexttoward( 0.0L, s ) = " << y7 << " " << type( y7 ) << "\n\n";
auto x8 = std::nextafter ( 0.0L, d ); // long double
auto y8 = std::nexttoward( 0.0L, d ); // long double
std::cout << "nextafter ( 0.0L, d ) = " << x8 << " " << type( x8 ) << '\n';
std::cout << "nexttoward( 0.0L, d ) = " << y8 << " " << type( y8 ) << "\n\n";
auto x9 = std::nextafter ( 0.0L, q ); // long double
auto y9 = std::nexttoward( 0.0L, q ); // long double
std::cout << "nextafter ( 0.0L, q ) = " << x9 << " " << type( x9 ) << '\n';
std::cout << "nexttoward( 0.0L, q ) = " << y9 << " " << type( y9 ) << "\n\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
至少在我的笔记本电脑上(2.3 GHz Core i9、macOS 12),对于正常数字,性能相似(3.0e-9 秒),但如果from低于正常值,nexttoward则比nextafter(5.0e-8 与 4.5e-9)慢约 11 倍秒)。
| 归档时间: |
|
| 查看次数: |
1517 次 |
| 最近记录: |