2015-02-28 9 views
1

Я довольно новичок в этой теме и не мог узнать причину: иногда программа работает, иногда нет (после того, как задал вопрос, она просто не хочет принимать в моих ответах, чем я могу писать столько, сколько я хочу, это не отвечает, просто перечислить номера, я tiped в)Итерация Ньютона Рафсона в ловушке бесконечного цикла

#include <stdio.h> 

float abszolut (float szam) 
{ 
    float abszoluterteke; 
    if (szam >=0) 
     abszoluterteke = szam; 
    else 
     abszoluterteke = -szam; 
    return abszoluterteke; 
} 

float negyzetgyok (float szam) 
{ 
    float pontossag = 0.000001; 
    float tipp = 1; 
    if (szam <0) 
    { 
     printf ("Megszakítás elfogadva! \nKöszönjük, hogy programunkat választotta!\n"); 
     return -1; 
    } 
    else 
     {while (abszolut (tipp*tipp-szam) >= pontossag) 
      tipp = (szam/tipp + tipp)/2; 
     return tipp; 
    } 
} 

int main (void) 
{ 
    float alap, eredmeny; 
    for (;;) 
    { 
     printf ("Melyik számnak szeretnéd meghatározni a négyzetgyökét ilyen módszerrel?\n"); 
     scanf ("%f", &alap); 
     eredmeny = negyzetgyok (alap); 
     if (eredmeny == -1) 
      return 1; 
     else 
     printf ("A(z) %f négyzetgyöke megfelelő közelítéssel: %f\n", alap, eredmeny); 




    } 
    return 0; 
} 
+0

Основная цель состояла в том, чтобы спросить в номере, узнать его квадратный корень, используя метод Ньютона-Рафсона, если его значение положительное и прервать процесс, если его отрицательный. –

+0

Можете ли вы предоставить данные, для которых работает программа, и данные, для которых она не работает? – VolAnd

+0

Он работает от 1 до 41 и не работает ни для чего выше 41 – Taimour

ответ

1

Изменить для abszolut (tipp*tipp-szam) >= pontossag*szam

петля в то время как должен остановить один раз tipp*tipp находится недалеко от szam. Но IEEE floating point computations имеют ограниченную точность: около 7 цифр для float и 15 цифр для double.

Таким образом, ошибка на float szam составляет около 0.0000001*szam. То же самое для tipp. Следовательно, ошибка на tipp*tipp-szam выше, чем 0.0000001*szam. Если szam велико, эта ошибка вряд ли станет ниже 0.000001. Даже если используется точность double, вполне вероятно, что while (abszolut (tipp*tipp-szam) >= pontossag) запускает бесконечный цикл для очень больших чисел.

С другой стороны, , что происходит, если szam очень мало, скажем, 1e-10? Цикл while преждевременно выходит, а квадратный корень из 1e-10 вычисляется как-то около 1e-3, а не 1e-5 ... Относительная ошибка составляет около 10000% ... И использование double ничего не меняет!

Чтобы избежать этого, вы можете изменить для abszolut (tipp*tipp-szam) >= pontossag*szam.

Обратите внимание, что обе стороны имеют одинаковую размерность. Если szam были в квадратных футах, tipp был бы в футах и ​​pontossag, точность, безразмерная. Хорошая практика - сравнивать вещи, имеющие одинаковый размер.

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

Чтобы избежать бесконечного цикла, добавьте счетчик int i; и выйдите из цикла while, если количество итераций равно 100. 100 должно быть достаточным, так как ваш Newton-Raphson iteration имеет квадратичную конвергенцию.

+0

Plus one. Это правильный ответ. –

0

С кодом возникает ряд проблем.

Условие выхода в вашей петле является ошибочным.
Проблема с вашим квадратным корневым алгоритмом заключается в использовании ограничения ошибки pontossag. Ваш алгоритм даст ошибочные результаты для очень маленьких чисел, и он будет циклически навсегда для чисел, больших 20 или около того. Чтобы исправить это, измените тест цикла с abszolut (tipp*tipp-szam) >= pontossag на abszolut (tipp*tipp-szam) >= pontossag*szam.

Вы не проверяете все проблемы.
Если ваш компьютер использует плавающие точки IEEE 754, ваш алгоритм работает. Это просто удача. Никогда не полагайтесь на удачу при выполнении численного программирования. Легко вводить бесконечность. Например, 3.5e38 (3500000000000000000000000000000000000000000) делает трюк с номерами с одной точностью (float).Ваша функция negyzetgyok следует проверить на бесконечности:

if (isinf (szam)) 
{ 
    return szam; 
} 

Вы можете сделать гораздо лучше, чем начальное приближение 1,0 как квадратный корень.
Исходное предположение 1.0 против 3.4e38 означает много ненужных циклов. Быстрый и простой способ сформировать хорошее исходное предположение - воспользоваться тем фактом, что числа с плавающей запятой представлены внутри как (1+fractional_part)*2^exponent. Хорошая первая догадка - 1*2^(exponent/2). С одинарной точностью чисел,

int expo; 
float tipp; 
frexpf (szam, &expo); 
tipp = ldexpf (1.0f, n/2); 

Вы используете %f, а не %g для анализа чисел с плавающей запятой.
Формат% g может анализировать все, что может быть проанализировано с помощью формата% f, а также намного больше.

Вы не проверяете статус fscanf. Введите x, когда будет предложено ввести номер. Сканер прочитает этот символ, который останавливает сканирование. Сканер положит этот символ (x) обратно в буфер ввода и вернет 0, указывая, что ничего не было отсканировано. В следующий раз сканер снова прочитает символ x, снова вернет этот символ во входной буфер и снова вернет 0. Бесконечный цикл! Всегда проверяйте состояние любого из семейств функций scanf, чтобы проверить, сканирует ли сканер количество ожидаемых элементов.

Вы используете fscanf.
На этом сайте есть ряд существующих вопросов и ответов, в которых рассматриваются многие проблемы с использованием fscanf для чтения из файла. Это особенно важно при чтении данных, генерируемых человеком. Люди ошибаются. Игнорирование того, что люди делают ошибки при вводе данных, является ошибкой программирования. Лучшим подходом было бы считывание строки в буфер с использованием frets и разбор этой строки с помощью sscanf.