Бесконечный цикл нуля в таблице

#c

Вопрос:

этот код делит окружность на X частей и отображает таблицу значений радиана каждой части. но я получаю бесконечный цикл отображения 0, когда я использую значение, превышающее 6, со значением ниже 6 я получаю «0 1 2 3 4 5 6». Кажется, что отображаемое значение также не является плавающим. У меня есть код, использующий степени, и он отлично работает.

 #include <iostream>
using namespace std;


#define pi 3.14159265359
#define pi2 6.28318530718

int nbObjets = 0;

void objetsPositionRadian(int tab[], int nbObjets);


int main(){

    int tabRadian[] = {0};
    
    std::cout << "Nombre d'objets ? ";
    std::cin >> nbObjets;

    objetsPositionRadian(tabRadian, nbObjets);

    return 0;
}

void objetsPositionRadian(int tab[], int nbObjets){
    float radian = (360/nbObjets) * (pi/180);
    for (int i = 0; i < pi2; i =radian){
        std::cout << i << " ";
    }
    std::cout << endl;
}

 

Комментарии:

1. i =radian добавляет float меньше 1 к int , это ничего не даст.

2. спасибо, это была моя ошибка, теперь работает нормально

3. У вас та же основная проблема в другом месте. Если вы запросите более 360 объектов, (360 / nbObjets) это станет нулем, и вы снова получите бесконечный цикл. Изменение 360 на 360.0 должно исправить это.

4. Независимо от того, работает ли он «нормально», for цикл должен использовать целые числа, а не плавающую точку в качестве условий начала / продолжения / остановки. Причина в том, что ваш цикл не будет гарантированно повторяться столько раз, сколько вы ожидаете, если вы используете переменные цикла с плавающей запятой. Если вам нужно n время цикла, то i следует перейти от 0 к n и внутри цикла масштабировать i значение до значения с плавающей точкой , которое вы хотите использовать.

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

Ответ №1:

Очевидный ход здесь состоит в том, чтобы изменить i свой цикл на a double (или float ) вместо an int .

Наряду с этим при вычислении radian 360/nbObjets выполняется целочисленное деление, поэтому, если nbObjets значение > 360, оно даст результат 0. Изменение 360 на 360.0 исправляет эту проблему.

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

Эта проблема возникает из-за кумулятивных ошибок при добавлении radian i в цикл. Вместо того, чтобы делать это, вы почти наверняка хотите что-то в этом заказе:

 for (int i=0; i<nbObjets; i  )
    cout << i * radian;
 

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

Комментарии:

1. ваше решение кажется более стабильным с проблемой поплавка, разве double тоже не дает достаточной точности ?

2. @CTRL-Z: в зависимости от количества объектов double может быть достаточно просто использовать. Навскидку я немного не уверен, сколько именно объектов у вас может быть, прежде чем все пойдет не так.

3. теперь, когда я осознаю эту нестабильную ситуацию, я думаю, что ваше решение-лучшее решение.

4. @CTRL-Z: Конечно.

5. @CTRL-Z double имеет большую точность, чем float так что это почти всегда лучший выбор.

Ответ №2:

Вы делаете две опасные вещи в следующих двух строках:

     float radian = (360/nbObjets) * (pi/180);
    for (int i = 0; i < pi2; i =radian)
 

Во-первых: nbObject определяется как целое число. В результате 360/nbObjects будет вычислено целое число (например, для 7 результатом будет 51, а не число с плавающей запятой).

Затем вы определяете i как целое число. Когда вы добавляете к нему число, меньшее 1, оно всегда будет оставаться неизменным.

Поэтому я советую вам при необходимости использовать больше чисел с плавающей запятой, как в этом предложении:

     double radian = ((double)360/nbObjets) * (pi/180); // first typecast 360 as a
                                                       // floating point, in order 
                                                       // to enforce floating 
                                                       // point arithmetic.
    for (double i = 0; i < pi2; i =radian)
 

Это должно работать лучше.

Комментарии:

1. Это страдает от состояния, упомянутого в комментариях. Нет никакой гарантии, что цикл всегда будет повторяться одно и то же количество раз из-за неточности с плавающей запятой.

2. @PaulMcKenzie: Он всегда должен повторяться одно и то же количество раз при каждом запуске. Плавающие точки детерминированы, просто… не интуитивно. О, ты имел в виду повторение цикла столько же раз, сколько и раньше? Это правда

3. @MooingDuck: В этом случае я бы сказал, что важным моментом является то, что количество результатов, которые вы получаете, может не соответствовать количеству объектов, для которых вы попросили его вычислить позиции.

4. @MooingDuck Изменение параметров компилятора / компилятора может привести к различным результатам с точки зрения количества выполняемых итераций.

5. спасибо за вашу помощь, я искал в неправильном направлении.