Быстрая, неточная функция sin без поиска

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

Ряд Тейлора греха слишком медленный, так как мне нужно было бы вычислить до 9-й степени x, чтобы получить полный период.

Какие-либо предложения?

РЕДАКТИРОВАТЬ: извините, я не упомянул, я не могу использовать таблицу поиска, так как она находится в вершинном шейдере. Таблица поиска будет включать образец текстуры, который в вершинном шейдере работает медленнее, чем встроенная функция sin. Он не должен быть каким-либо образом точным, он просто должен выглядеть красиво.


person Hannesh    schedule 23.08.2011    source источник
comment
Является ли ряд Тейлора медленным для x между 0 и π/2? Если это приемлемо, вы можете использовать симметрии греха, чтобы вычислить его для других значений.   -  person lhf    schedule 24.08.2011


Ответы (5)


Используйте приближение Чебышева для необходимого количества терминов. Это особенно легко, если ваши входные углы ограничены хорошим поведением (-π .. +π или 0 .. 2π), поэтому вам не нужно сначала уменьшать аргумент до разумного значения. Вы можете использовать 2 или 3 термина вместо 9.

person Jonathan Leffler    schedule 23.08.2011
comment
+1 за Чебышева, это лучший способ. Тем не менее, сокращение диапазона является огромным преимуществом, если это возможно. - person Jason S; 24.08.2011

Вы можете создать справочную таблицу со значениями sin для некоторых значений и использовать линейную интерполяцию между этими значениями.

person Mircea Ispas    schedule 23.08.2011
comment
@super заголовок был отредактирован. Вы хоть редактирование/историю читали? :) - person Mircea Ispas; 01.11.2017
comment
как насчет истории этого ответа - person ; 01.11.2017

Приближение рациональной алгебраической функции к sin (x), действительное от нуля до π / 2:

f = (C1 * x) / (C2 * x^2 + 1.) 

с константами:

c1 =   1.043406062 
c2 =  .2508691922 

Эти константы были найдены методом наименьших квадратов. (Используя подпрограмму DHFTI от Lawson & Hanson).

Если вход находится за пределами [0, 2π], вам нужно взять x по модулю 2 π.
Чтобы обрабатывать отрицательные числа, вам нужно написать что-то вроде:

t = MOD(t, twopi)
IF (t < 0.) t = t + twopi

Затем, чтобы расширить диапазон от 0 до 2π, уменьшите ввод примерно так:

IF (t  < pi) THEN
  IF (t < pi/2) THEN
    x = t
  ELSE
      x = pi - t
   END IF
 ELSE 
   IF (t < 1.5 * pi) THEN
     x = t - pi
  ELSE
     x = twopi - t
   END IF
END IF

Затем рассчитайте:

f = (C1 * x) / (C2 * x*x + 1.0)
IF (t > pi) f = -f

Результаты должны быть в пределах примерно 5% от реального синуса.

person andy_a    schedule 07.11.2013
comment
Я отредактировал свой ответ в ответ на эту критику. Чтобы уточнить, рациональная функция f = (c1 * x) / (c2 * x^2 + 1) действительна от 0 до π/2. IF-блок редукции расширяет его от 0 до 2π, но вы должны сделать это заранее. Сначала вы должны взять мод 2π. Лоусон и Хэнсон написали подпрограмму наименьших квадратов, которая помогает найти константы, для этой цели подойдет любая подпрограмма наименьших квадратов. Если вы можете сжать 13 строк кода исправления в одну строку, покажите ее мне. - person andy_a; 02.04.2021
comment
Оптимизировано для относительной ошибки вместо абсолютной ошибки: float sin_rational (float a) { return (1.01815748f * a) / (0.23133484f * a * a + 1.0f); } - person njuffa; 03.04.2021
comment
Энди, я отозвал свой отрицательный голос, потому что ценю ответ. Я вернусь к вам по поводу остальных, когда я найду время, чтобы сделать это. - person Mike Nakis; 04.04.2021
comment
Приношу свои извинения, функция действительно работает при правильной реализации, чего у меня изначально не получилось. Однако мой тест показывает, что он значительно медленнее, чем встроенная функция Math.sin() Java, работающая на современном ПК, и мои тесты показали, что он значительно менее точен, чем альтернативный метод (см. stackoverflow.com/a/28050328/773113), который также оказывается намного быстрее, чем встроенная функция Java . - person Mike Nakis; 04.04.2021

Ну, вы не говорите, насколько точна она вам нужна. Синус можно аппроксимировать прямыми линиями наклона 2/pi и -2/pi на интервалах [0, pi/2], [pi/2, 3*pi/2], [3*pi/2, 2*pi ]. Это приближение можно получить за счет умножения и сложения после уменьшения угла по модулю 2*pi.

person President James K. Polk    schedule 24.08.2011
comment
Ну, точнее: P В этом смысле не обязательно быть «точным», меня не волнует нахождение приблизительного синуса заданного угла. Я просто пытаюсь найти гладкую функцию, похожую на волну. - person Hannesh; 24.08.2011
comment
@Hannesh: Ха, хорошо, по крайней мере, я не сказал, что это можно аппроксимировать функцией f (x) = 0. - person President James K. Polk; 24.08.2011

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

person Ernest Friedman-Hill    schedule 23.08.2011
comment
-1 потому что это просто неправда сегодня, я думаю, особенно когда тактовые частоты вырастут в будущем - person Quonux; 13.02.2014