Что самый быстрый путь состоит в том, чтобы вычислить грех и потому что вместе?

Я хотел бы вычислить и синус и косинус значения вместе (например, для создания матрицы вращения). Конечно, я мог вычислить их отдельно один за другим как a = cos(x); b = sin(x);, но интересно, существует ли более быстрый путь при необходимости в обоих значениях.

Править: Суммировать ответы до сих пор:

  • Vlad сказал, что существует команда asm FSINCOS вычисления их обоих (в почти то же время как вызов к FSIN один)

  • Как замеченный Chi, эта оптимизация иногда уже делается компилятором (при использовании флагов оптимизации).

  • caf указал, который функционирует sincos и sincosf вероятно, доступны и может быть назван непосредственно только включая math.h

  • подход tanascius использования справочной таблицы обсужден спорный. (Однако на моем компьютере и в сценарии сравнительного теста это работает 3x быстрее, чем sincos почти с той же точностью для 32-разрядных плавающих точек.)

  • Joel Goodwin связался с интересным подходом чрезвычайно быстрого метода приближенных вычислений с довольно хорошим accuray (для меня, это еще быстрее затем поиск по таблице),

98
задан Community 23 May 2017 в 12:02
поделиться

15 ответов

Современные процессоры Intel / AMD имеют инструкцию FSINCOS для одновременного вычисления синусоидальных и косинусных функций. Если вам нужна сильная оптимизация, возможно, вам стоит ее использовать.

Вот небольшой пример: http://home.broadpark.no/~alein/fsincos.html

Вот еще один пример (для MSVC): http: //www.codeguru .com / forum / showthread.php? t = 328669

Вот еще один пример (с gcc): http://www.allegro.cc/forums/thread/588470

Надеюсь, что один из них помогает. (Я сам не использовал эту инструкцию, извините.)

Поскольку они поддерживаются на уровне процессора, я ожидаю, что они будут намного быстрее, чем поиск по таблицам.

Редактировать:
Википедия предполагает, что FSINCOS был добавлен на 387 процессорах, поэтому вы вряд ли найдете процессор, который его не поддерживает.

Правка:
В документации Intel указано, что FSINCOS примерно в 5 раз медленнее, чем FDIV (т.е. деление с плавающей запятой).

Изменить:
Обратите внимание, что не все современные компиляторы оптимизируют вычисление синуса и косинуса при вызове FSINCOS . В частности, мой VS 2008 этого не делал.

Редактировать:
Первая ссылка в качестве примера не работает, но есть версия на Wayback Machine .

51
ответ дан 24 November 2019 в 05:16
поделиться

Думали ли вы об объявлении таблиц поиска для двух функций? Вам все равно придется «вычислять» sin (x) и cos (x), но это будет значительно быстрее, если вам не нужна высокая степень точности.

0
ответ дан 24 November 2019 в 05:16
поделиться

На этой странице форума есть очень интересные материалы, направленные на быстрый и быстрый поиск хороших приближений: http://www.devmaster.net/forums/showthread.php?t= 5784

Отказ от ответственности: Сам не использовал эти материалы.

Обновление от 22 февраля 2018 г .: Wayback Machine - единственный способ перейти на исходную страницу сейчас: https://web.archive.org/web/20130927121234/http://devmaster.net/posts/9648/ быстрый и точный синус-косинус

8
ответ дан 24 November 2019 в 05:16
поделиться

Что касается творческого подхода, как насчет расширения серии Тейлора? Поскольку у них схожие термины, вы можете сделать что-то вроде следующего псевдо:

numerator = x
denominator = 1
sine = x
cosine = 1
op = -1
fact = 1

while (not enough precision) {
    fact++
    denominator *= fact
    numerator *= x

    cosine += op * numerator / denominator

    fact++
    denominator *= fact
    numerator *= x

    sine += op * numerator / denominator

    op *= -1
}

Это означает, что вы делаете что-то вроде этого: начиная с x и 1 для sin и косинуса, следуйте шаблону - вычтите x ^ 2/2! из косинуса вычтите x ^ 3/3! из синуса прибавить x ^ 4/4! к косинусу прибавить x ^ 5/5! to sine ...

Я понятия не имею, будет ли это производительным. Если вам нужна меньшая точность, чем дают встроенные функции sin () и cos (), это может быть вариантом.

2
ответ дан 24 November 2019 в 05:16
поделиться

Я не верю, что справочные таблицы обязательно являются хорошей идеей для решения этой проблемы. Если ваши требования к точности не очень низкие, таблица должна быть очень большой. А современные процессоры могут выполнять много вычислений, пока значение извлекается из основной памяти. Это не один из тех вопросов, на которые можно правильно ответить с помощью аргументов (даже не моих), тестирования, измерения и рассмотрения данных.

Но я бы посмотрел на быстрые реализации SinCos, которые вы найдете в таких библиотеках, как AMD ACML и Intel MKL.

5
ответ дан 24 November 2019 в 05:16
поделиться

Когда производительность критична для такого рода вещей, нет ничего необычного во введении таблицы поиска.

2
ответ дан 24 November 2019 в 05:16
поделиться

Современные процессоры x86 имеют инструкцию fsincos, которая будет делать именно то, что вы просите - вычислять sin и cos одновременно. Хороший оптимизирующий компилятор должен обнаруживать код, который вычисляет sin и cos для одного и того же значения, и использовать команду fsincos для его выполнения.

Чтобы это сработало, потребовалось немного перевернуть флаги компилятора, но:

$ gcc --version
i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5488)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cat main.c
#include <math.h> 

struct Sin_cos {double sin; double cos;};

struct Sin_cos fsincos(double val) {
  struct Sin_cos r;
  r.sin = sin(val);
  r.cos = cos(val);
  return r;
}

$ gcc -c -S -O3 -ffast-math -mfpmath=387 main.c -o main.s

$ cat main.s
    .text
    .align 4,0x90
.globl _fsincos
_fsincos:
    pushl   %ebp
    movl    %esp, %ebp
    fldl    12(%ebp)
    fsincos
    movl    8(%ebp), %eax
    fstpl   8(%eax)
    fstpl   (%eax)
    leave
    ret $4
    .subsections_via_symbols

Тада, он использует инструкцию fsincos!

38
ответ дан 24 November 2019 в 05:16
поделиться

Если вы используете библиотеку GNU C, вы можете:

#define _GNU_SOURCE
#include <math.h>

и получите объявления sincos () , sincosf () и sincosl () функции, которые вычисляют оба значения вместе - вероятно, самым быстрым способом для вашей целевой архитектуры.

8
ответ дан 24 November 2019 в 05:16
поделиться

Вы можете вычислить любое из них, а затем использовать идентификатор:

cos(x)2 = 1 - sin(x)2

, но, как говорит @tanascius, заранее вычисленная таблица - это лучший вариант.

12
ответ дан 24 November 2019 в 05:16
поделиться

Технически этого можно добиться, используя комплексные числа и формулу Эйлера . Таким образом, что-то вроде (C ++)

complex<double> res = exp(complex<double>(0, x));
// or equivalent
complex<double> res = polar<double>(1, x);
double sin_x = res.imag();
double cos_x = res.real();

должно дать вам синус и косинус за один шаг. Как это делается внутри, зависит от используемого компилятора и библиотеки. Это может (и может) занять больше времени, чтобы сделать это таким образом (просто потому, что формула Эйлера в основном используется для вычисления комплекса exp с использованием sin и cos - а не наоборот), но возможна теоретическая оптимизация.


Править

Заголовки в для GNU C ++ 4.2 используют явные вычисления sin и cos внутри полярных ], так что там он не будет выглядеть слишком хорошо для оптимизации, если компилятор не произведет магию (см. переключатели -ffast-math и -mfpmath , как написано в Ответ Чи ).

13
ответ дан 24 November 2019 в 05:16
поделиться

Когда вам нужна производительность, вы можете использовать предварительно вычисленную таблицу sin / cos (подойдет одна таблица, сохраненная в виде словаря). Ну, это зависит от необходимой точности (возможно, таблица будет слишком большой), но это должно быть очень быстро.

13
ответ дан 24 November 2019 в 05:16
поделиться

Если вы хотите использовать коммерческий продукт и одновременно рассчитываете несколько вычислений sin / cos (чтобы вы могли использовать векторные функции), вам следует обратиться к библиотеке Intel Math Kernel Library.

Он имеет функцию sincos

Согласно этой документации, он в среднем составляет 13,08 тактов на элемент в дуэте ядра 2 в режиме высокой точности, что, я думаю, будет даже быстрее, чем fsincos.

3
ответ дан 24 November 2019 в 05:16
поделиться

Многие математические библиотеки C, как указывает caf, уже имеют sincos (). Заметным исключением является MSVC.

  • Sun использует sincos () по крайней мере с 1987 года (двадцать три года; у меня есть бумажная страница руководства)
  • HPUX 11 имел его в 1997 году (но его нет в HPUX 10.20)
  • Добавлено в glibc в версии 2.1 (февраль 1999 г.)
  • Стало встроенным в gcc 3.4 (2004 г.), __builtin_sincos ().

Что касается поиска, Эрик С. Реймонд в Art of Unix Programming (2004) (глава 12) прямо говорит, что это плохая идея (в настоящий момент):

«Другой пример - это предварительное вычисление небольших таблиц - например, таблица sin (x) по градусам для оптимизации вращений в движке трехмерной графики будет занимать 365 × 4 байта на современной машине. До того, как процессоры стали достаточно быстрее памяти, чтобы требовать кэширования, это была очевидная оптимизация скорости . В настоящее время может быть быстрее каждый раз пересчитывать , чем платить за процент дополнительных промахи в кэше, вызванные таблицей .

"Но в будущем это может измениться снова, когда кеш станет больше. В целом, многие оптимизации являются временными и могут легко изменить {{1} }} в пессимизацию по мере изменения соотношений затрат. Единственный способ узнать это - измерить и увидеть ". (Из Искусство программирования Unix )

Но, судя по обсуждению выше, не все согласны.

{ {1}}
7
ответ дан 24 November 2019 в 05:16
поделиться

Я опубликовал решение, включающее встроенную сборку ARM, способную вычислять как синус, так и косинус двух углов одновременно: Быстрый синус / косинус для ARMv7 + NEON

​​
1
ответ дан 24 November 2019 в 05:16
поделиться

Эта статья показывает, как построить параболический алгоритм, который генерирует и синус, и косинус:

DSP Trick: Simultaneous Parabolic Approximation of Sin and Cos

http://www.dspguru.com/dsp/tricks/parabolic-approximation-of-sin-and-cos

3
ответ дан 24 November 2019 в 05:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: