Подтвердить что ты не робот

Pi в Objective C

Я продолжаю получать ошибки в моем iPhone-программировании, когда я пытаюсь использовать pi. Я пытаюсь

    float pNumber = 100*cos(2 * pi * (days/23));

Но я получаю ошибки, которые говорят:

_pi, на который ссылается

_pi $non_lazy_ptr

Я видел где-то в Интернете, чтобы использовать M_PI, и он компилируется, но я не думаю, что он дает мне правильный расчет.

Когда я пытаюсь:

    float pNumber = 100*cos(2 * M_PI * (15746/23));

Я получаю 0

Спасибо

4b9b3361

Ответ 1

  • Целочисленное деление, вероятно, должно быть принудительно введено в число с плавающей точкой (приведение одного из чисел к двойному - или использовать обозначение 23.0, чтобы указать, что вы хотите деление с плавающей запятой).
  • Попробуйте распечатать M_PI и посмотреть, что он говорит (printf("M_PI = %16.9g\n", M_PI); на C).
  • Включили ли вы объявление для cos()? Если нет, его можно интерпретировать как функцию, возвращающую целое число (#include <math.h> возможно).

Пример кода (тестируется в C на Solaris 10 SPARC с GCC 4.3.3):

#include <math.h>
#include <stdio.h>

int main(void)
{
    float pNumber = 100*cos(2 * M_PI * (15746/23));
    printf("M_PI = %16.9g\n", M_PI);
    printf("pNum = %16.9g\n", pNumber);
    pNumber = 100*cos(2 * M_PI * (15746/23.0));
    printf("pNum = %16.9g\n", pNumber);
    return 0;
}

Пример вывода:

M_PI =       3.14159265
pNum =              100
pNum =      -77.5711288

Ответ 2

C/С++ и, следовательно, Objective C/С++ не продвигает целые числа при плавании при нормальном делении.

Итак, в C/С++ выражение 15746/23 оценивается как 567, а не 567.71207, как вы могли бы наивно ожидать.

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

float pNumber = 100*cos(2 * M_PI * (15746/23.0));

100 будет автоматически повышаться, потому что cos возвращает float (фактически двойное, но я буду игнорировать проблемы с плоской/двойной ошибкой). 2 продвигается до поплавка, потому что M_PI является поплавком. И 15746 продвигается к поплавку, потому что 23.0 является плавающей точкой.

Однако было бы не повредить добавление .0 ко всем константам, то есть:

float pNumber = 100.0*cos(2.0 * M_PI * (15746.0/23.0));

Ответ 3

Задача - целочисленное деление в самой внутренней части выражения, которое усекает значение (опуская дробную часть). Один из вариантов, как уже упоминалось, состоит в том, чтобы сделать каждую константу числом с плавающей запятой, добавив после нее ".0" или "f". Кроме того, вы можете полностью исключить круглые скобки из самого внутреннего выражения. Так как M_PI - число с плавающей запятой, а умножение на C лево-ассоциативное (это означает, что это происходит слева направо), первое умножение (2 * M_PI) будет повышаться до float, как и каждый последующий умножить. Поскольку cos() возвращает float, pNumber будет назначен float, не выполнив никакого целочисленного деления, следовательно, не будет потери точности. (Примечание. Обычно не разумно рассчитывать на ассоциативность или приоритет оператора, но в этом случае я просто пытаюсь продемонстрировать, что это действительно сработает.)

В том, что касается диапазона чисел, которые вы должны ожидать, напомните, что косинус (немодифицированный) варьируется от -1 до +1, а не от 0 до 1, так что вы действительно видите -100 до 100 (теоретически). Чтобы получить правильный диапазон, вам нужно добавить 1, а затем умножить на 50.

Кстати, ошибки компиляции, которые вы получаете в первом случае, связаны с тем, что pi не определен. Рекомендации по использованию M_PI верны - для математических констант всегда разумнее (и более последовательно) использовать то, что предоставляет система. Если вам интересно, на Leopard эти константы # определены в Math.h, строки 528-540. Вы можете открыть файл, используя File > Open Quickly... (Cmd-Shift-D) и набрав "Math.h" или дважды щелкнув по M_PI в вашем коде, удерживая Command.

Ответ 4

Зачем использовать синусоиду в первую очередь?

Если цель состоит в том, чтобы иметь размер от 0 до 100, а затем 100 до 0 через 23 дня, вы можете использовать:

// x ranges from 0 to 2
float x = (days % 23)/11.5;
// pNumber is a saw ranging from 0 to 100
float pNumber = 100 * abs(x - 1);

Вы также можете заменить x на косинус, если вы действительно хотите его, как 2 * pi/23 ~ = 0.273, у вас есть

float x = 1 + cos((days % 23)*0.273);