在C库math.h中,有一个sincos函数非常高效,因为它计算正弦和余弦的时间更接近于对sin()或cos()的单次调用,而不是调用两者的总时间。C++标准库中有这样的函数吗?
math.h
sincos
sin()
cos()
mzaanser1#
c++标准库中没有这样的函数吗?不,很不幸没有。在C库math.h中,有一个sincos函数在Linux上,它可以作为GNU Extension使用。这在C中也不是标准的。
ars1skjm2#
只需分别使用sin和cos并打开优化。C编译器非常擅长优化,他们可能会意识到你正在计算同一个变量的正弦和余弦。如果你想确保sure,你可以检查生成的程序集(对于gcc使用-S选项),看看它生成了什么。编译器可能会优化任何对sin或cos的调用,而只使用SSE指令来计算它。我不确定SSE是否有sincos操作码,但即使单独计算它们也比调用任何编译器不会优化的sincos函数快。
sin
cos
aiqt4smr3#
虽然没有标准的C++库函数,但你可以很快地定义一个模板函数:
template <class S> std::pair<S,S> sincos(S arg) { return { std::sin(arg), std::cos(arg) }; }
然后你可以在一行中得到结果(使用C++ 17):
auto [s, c] = sincos(arg);
如果您经常这样做,它会非常方便,节省空间,并且是自文档化的,所以我强烈推荐它。如果您担心性能问题,请不要担心。当使用优化编译时,它应该产生与单独调用sin和cos完全相同的代码。您可以在以下测试代码中确认clang++ -std=c++17 -S -o - -c -O3 sincos.cpp的情况:
clang++ -std=c++17 -S -o - -c -O3 sincos.cpp
#include <cmath> #include <utility> #include <iostream> template <class S> std::pair<S,S> sincos(S arg) { return { std::sin(arg), std::cos(arg) }; } void testPair(double a) { auto [s,c] = sincos(a); std::cout << s << ", " << c << '\n'; } void testSeparate(double a) { double s = std::sin(a); double c = std::cos(a); std::cout << s << ", " << c << '\n'; }
在使用clang的MacOS上,两个测试函数都编译为调用___sincos_stret执行组合计算的完全相同的程序集(减去名称更改)(参见https://stackoverflow.com/a/19017286/973580)。
___sincos_stret
u7up0aaq4#
没有这样的内置标准函数。下面是一次计算sincos的直接汇编代码(gcc语法)这仅在需要80位精度时。x87指令没有矢量化,因此除非需要long double(实际上使用了80位),否则它不会提高性能。即使这样,单独的sinl和cosl也将被优化为如下结果。
gcc
long double
sinl
cosl
这不是一个好的实践(在大多数情况下,既不是直接使用汇编也不是使用x87)..但这是一个有趣的练习,所以这里是结果。
long double input = 5L; long double sin = input; long double cos = 0L; __asm__ ( "fldt %0;" "fsincos;" // sincos in one instruction "fstpt %1;" "fstpt %0;" : "+m" (sin), "+m" (cos) ); printf("sin %.19Lf cos %.19Lf \n", sin, cos);
mum43rcc5#
相反,你可以使用这个函数,它只使用std::cos和std::sqrt(还没有实际测试过,它可能不工作)
template <typename T> constexpr inline static void sincos(const T &x, T* sin, T* cos) { (*cos) = std::cos(x); (*sin) = std::sqrt(static_cast<T>(1) - *cos**cos); if ((int)(x / M_PI) & 1) (*sin) = -(*sin); }
5条答案
按热度按时间mzaanser1#
c++标准库中没有这样的函数吗?
不,很不幸没有。
在C库math.h中,有一个sincos函数
在Linux上,它可以作为GNU Extension使用。这在C中也不是标准的。
ars1skjm2#
只需分别使用sin和cos并打开优化。C编译器非常擅长优化,他们可能会意识到你正在计算同一个变量的正弦和余弦。如果你想确保sure,你可以检查生成的程序集(对于gcc使用-S选项),看看它生成了什么。
编译器可能会优化任何对
sin
或cos
的调用,而只使用SSE指令来计算它。我不确定SSE是否有sincos
操作码,但即使单独计算它们也比调用任何编译器不会优化的sincos
函数快。aiqt4smr3#
虽然没有标准的C++库函数,但你可以很快地定义一个模板函数:
然后你可以在一行中得到结果(使用C++ 17):
如果您经常这样做,它会非常方便,节省空间,并且是自文档化的,所以我强烈推荐它。如果您担心性能问题,请不要担心。当使用优化编译时,它应该产生与单独调用sin和cos完全相同的代码。您可以在以下测试代码中确认
clang++ -std=c++17 -S -o - -c -O3 sincos.cpp
的情况:在使用clang的MacOS上,两个测试函数都编译为调用
___sincos_stret
执行组合计算的完全相同的程序集(减去名称更改)(参见https://stackoverflow.com/a/19017286/973580)。u7up0aaq4#
没有这样的内置标准函数。下面是一次计算sincos的直接汇编代码(
gcc
语法)这仅在需要80位精度时。x87指令没有矢量化,因此除非需要
long double
(实际上使用了80位),否则它不会提高性能。即使这样,单独的sinl
和cosl
也将被优化为如下结果。这不是一个好的实践(在大多数情况下,既不是直接使用汇编也不是使用x87)..但这是一个有趣的练习,所以这里是结果。
mum43rcc5#
相反,你可以使用这个函数,它只使用std::cos和std::sqrt(还没有实际测试过,它可能不工作)