Создание синуса таблицы поиска в C ++

голоса
10

Как я могу переписать следующий псевдокод в C ++?

real array sine_table[-1000..1000]
    for x from -1000 to 1000
        sine_table[x] := sine(pi * x / 1000)

Мне нужно создать sine_table таблицу поиска.

Задан 10/09/2010 в 22:57
источник пользователем
На других языках...                            


6 ответов

голоса
6

Вы хотите , чтобы std::sin()функция от <cmath>.

Ответил 10/09/2010 в 23:00
источник пользователем

голоса
4
long double sine_table[2001];
for (int index = 0; index < 2001; index++)
{
    sine_table[index] = std::sin(PI * (index - 1000) / 1000.0);
}
Ответил 10/09/2010 в 23:03
источник пользователем

голоса
3


double table[1000] = {0};
for (int i = 1; i <= 1000; i++)
{
    sine_table[i-1] = std::sin(PI * i/ 1000.0);
}

double getSineValue(int multipleOfPi){ if(multipleOfPi == 0) return 0.0; int sign = 1; if(multipleOfPi < 0){ sign = -1;
} return signsine_table[signmultipleOfPi - 1]; }

Можно уменьшить длину массива до 500, с помощью трюкового греха (пи / 2 +/- угла) = +/- сова (угла). Так магазин грех и потому от 0 до пи / 4. Я не помню, с верхней части моей головы, но это увеличило скорость моей программы.

Ответил 11/09/2010 в 00:29
источник пользователем

голоса
25

Вы можете уменьшить размер вашего стола до 25% от оригинала только сохранение значений для первого квадранта, то есть для й в [0, пи / 2].

Чтобы сделать это, ваша процедура поиска просто необходимо отобразить все значения х в первом квадранте, используя простые тригонометрические тождества:

  • грех (х) = - sin (-x), на карту из квадранта IV в I
  • грех (х) = sin (пи - х), на карту из квадранта II в I

Для отображения из квадранта III в I, применяются оба тождества, то есть грех (х) = - sin (пи + х)

Является ли эта стратегия помогает зависит от того, сколько вопросов использования памяти в вашем случае. Но, кажется расточительным хранить в четыре раза больше значения, сколько вам нужно только, чтобы избежать сравнений и вычитания или два во время поиска.

Я вторая рекомендация Джереми измерить ли построение таблицы лучше, чем просто с помощью зОго :: sin (). Даже с оригинальным большим столом, вам придется провести циклы в течение каждого табличного преобразовать аргумент до ближайшего приращения пи / 1000, и вы потеряете некоторую точность в процессе.

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

  • грех (х) = х - х ^ 3/3! + Х ^ 5/5! ..., где ^ означает возведение в степень и! представляет факториал.

Конечно, для повышения эффективности, вы должны предвычислением факториалов и использовать нижние степеням х, чтобы вычислить более высокие, например, использование х ^ 3 при вычислении х ^ 5.

Один последний момент, усеченный ряд Тейлора выше, является более точным для значений ближе к нулю, так что его все еще стоит карты к первому или четвертому квадранту перед вычислением приблизительного синуса.

Приложение: Еще одно потенциальное улучшение на основе двух наблюдений:
1. Вы можете вычислить любую функцию Триг , если вы можете вычислить как синус и косинус в первом октанте [0, пи / 4]
2. Разложение в ряд Тейлора с центром в нуле более точным вблизи нуля

Так что если вы решили использовать усеченный ряд Тейлора, то вы можете повысить точность (или использовать меньшее количество терминов для подобной точности) путем картированием либо синус или косинус, чтобы получить угол в диапазоне [0, пи / 4] с использованием тождества как Sin (х) = соз (р / 2-х) и соз (х) = sin (пи / 2-х), в дополнение к приведенным выше (например, если х> пи / 4 раз вы сопоставили в первый квадрант.)

Или, если вы решите использовать табличный как для синуса и косинуса, вы можете получить с двумя меньшими таблицами, которые только покрыли диапазон [0, пи / 4] за счет другого возможного сравнения и вычитания на поиск для сопоставления меньший диапазон. После этого вы можете либо использовать меньше памяти для таблиц, или использовать ту же память, но обеспечивают более тонкую степень детализации и точности.

Ответил 11/09/2010 в 00:55
источник пользователем

голоса
4

Еще один момент: вызов тригонометрических функций является дорогой. если вы хотите, чтобы подготовить таблицу поиска для синусоиды с постоянным шагом - вы можете сэкономить время расчета, в счете некоторой потенциальной потери точности.

Рассмотрим ваш минимальный шаг является «». То есть, вам нужно грех (а), грех (2а), грех (3а), ...

Тогда вы можете сделать следующий трюк: сначала вычислить грех (а) и соз (а). Тогда для каждого последовательного шага используют следующие тригонометрические равенства:

  • Sin ([п + 1] * а) = Sin (п * а) * соз (а) + соз (п * а) * Sin (а)
  • сов ([п + 1] * а) = соз (п * а) * соз (а) - SIN (п * а) * Sin (а)

Недостатком этого способа является то, что во время этой процедуры накапливается ошибка округления.

Ответил 19/09/2010 в 18:37
источник пользователем

голоса
3

другое приближение из книги или что-то

streamin ramp;
streamout sine;

float x,rect,k,i,j;

x = ramp -0.5;

rect = x * (1 - x < 0 & 2);
k = (rect + 0.42493299) *(rect -0.5) * (rect - 0.92493302) ;
i = 0.436501 + (rect * (rect + 1.05802));
j = 1.21551 + (rect * (rect - 2.0580201));
sine = i*j*k*60.252201*x;

Полное обсуждение здесь: http://synthmaker.co.uk/forum/viewtopic.php?f=4&t=6457&st=0&sk=t&sd=a

Я полагаю, что вы знаете, что с помощью разделения намного медленнее, чем умножение на десятичное число, / 5 всегда медленнее, чем * 0,2

это всего лишь приближение.

также:

streamin ramp;
streamin x;  // 1.5 = Saw   3.142 = Sin   4.5 = SawSin
streamout sine;
float saw,saw2;
saw = (ramp * 2 - 1) * x;
saw2 = saw * saw;

sine = -0.166667 + saw2 * (0.00833333 + saw2 * (-0.000198409 + saw2 * (2.7526e-006+saw2 * -2.39e-008)));
sine = saw * (1+ saw2 * sine);
Ответил 29/03/2013 в 23:14
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more