Тригонометрическое уменьшение аргумента (уменьшение по модулю 2π) - PullRequest
0 голосов
/ 29 апреля 2018

Я пытаюсь создать калькулятор для греха и косинуса, который технически работает только в диапазоне 0-пи / 2. Прямо сейчас это может показаться глупым, но позже оно будет использовано, чтобы я мог использовать серию Тейлора.

У меня есть в основном работающая реализация, однако у меня возникает серьезная проблема, когда тэта имеет вид x * (pi / 2), где x - произвольное целое число. Может показаться, что на этих значениях иногда они выталкиваются в соседние квадранты, к которым они не принадлежат. Есть также некоторые случайные ошибки, которые я не могу объяснить.

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

Вот код для этого.

#define T_PI (2.0 * M_PI)
#define H_PI (0.5 * M_PI)
void sincos(float theta, float* cosine, float* cosine) {
  int mode;
  prepareForRange(&theta, cosine, sine);
  Assert(!(f < 0.0 || f > H_PI));
  *cosine = cos(theta);
  *sine = sin(theta);
  range_output(mode, cosine, sine);
}
void prepareForRange(float* theta, int* mode, float *cosine, float* sine) {
  if (*theta < 0.0) *theta += ceil(-*theta / T_PI) * T_PI;
  *mode = (int)floor(*theta / H_PI) % 4 + 1;
  *theta = fmodf(*theta, H_PI);
}
void range_output(int mode, float *cos, float *sin) {
  float temp;
  switch (mode) {
    case 1:
      break;
    case 2:
      temp = *cos;
      *cos = -*sin;
      *sin = temp;
      break;
    case 3:
      *cos = -*cos;
      *sin = -*sin;
      break;
    case 4:
      temp = *cos;
      *cos = *sin;
      *sin = -temp;
      break;
    default:
      break;
    }
}

1 Ответ

0 голосов
/ 29 апреля 2018

Вы сталкиваетесь с давней и часто непризнанной проблемной областью, которая называется уменьшение диапазона . Основная проблема заключается в том, что константа PI с плавающей запятой определяется только с точностью до 8 цифр, поэтому к тому времени, когда вы пытаетесь вычислить (x - n * PI) для n ~ 10 ^ 4, вы потеряли половину цифры точности в своих результатах и хуже, когда n становится больше. Простого программного решения этой проблемы не существует. Чтобы действительно решить эту проблему в моей собственной числовой библиотеке , мне пришлось эффективно реализовать арифметику с плавающей запятой произвольной точности и сохранить 320-значную (1078-битную) константу PI. Некоторые реализации libc эффективно делают это для вас, но не для всех, поэтому вы не можете с уверенностью предположить это.

...