c++ libstd同时计算sin和cos

qyzbxkaa  于 2023-07-01  发布在  其他
关注(0)|答案(5)|浏览(180)

在C库math.h中,有一个sincos函数非常高效,因为它计算正弦和余弦的时间更接近于对sin()cos()的单次调用,而不是调用两者的总时间。
C++标准库中有这样的函数吗?

mzaanser

mzaanser1#

c++标准库中没有这样的函数吗?
不,很不幸没有。
在C库math.h中,有一个sincos函数
在Linux上,它可以作为GNU Extension使用。这在C中也不是标准的。

ars1skjm

ars1skjm2#

只需分别使用sin和cos并打开优化。C编译器非常擅长优化,他们可能会意识到你正在计算同一个变量的正弦和余弦。如果你想确保sure,你可以检查生成的程序集(对于gcc使用-S选项),看看它生成了什么。
编译器可能会优化任何对sincos的调用,而只使用SSE指令来计算它。我不确定SSE是否有sincos操作码,但即使单独计算它们也比调用任何编译器不会优化的sincos函数快。

aiqt4smr

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的情况:

#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)。

u7up0aaq

u7up0aaq4#

没有这样的内置标准函数。下面是一次计算sincos的直接汇编代码(gcc语法)
这仅在需要80位精度时。x87指令没有矢量化,因此除非需要long double(实际上使用了80位),否则它不会提高性能。即使这样,单独的sinlcosl也将被优化为如下结果。

这不是一个好的实践(在大多数情况下,既不是直接使用汇编也不是使用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);
mum43rcc

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);
}

相关问题