Почему программа заканчивается еще до запуска? - PullRequest
0 голосов
/ 17 апреля 2019

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

Я изучаю c ++, я нашел в сети код, который реализует метод Ньютона-Рафсона для нахождения корня функции. Код довольно прост, как вы можете видеть из него, в начале он запрашивает требуемый допуск, и, если я даю «приличное» число, он отлично работает. Если вместо этого, когда он запрашивает допуск, я пишу что-то вроде 1e-600, программа немедленно завершает работу и выводится Enter starting value x: Failed to converge after 100 iterations.

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

Почему это происходит? Как программа может записать этот вывод, даже если она не пробовала цикл 100 раз?

Редактировать: Кажется, что все бессмысленное (слишком маленькие цифры, слова), которые я пишу, когда он запрашивает допуск, выдает pnew = 0,25, а затем код запускается 100 раз и дает сбой.

Код следующий:

#include <iostream>
#include <cmath>
using namespace std;
#define N 100    // Maximum number of iterations


int main() {

    double p, pnew;
    double f, dfdx;
    double tol;
    int i;

    cout << "Enter tolerance: ";
    cin >> tol;
    cout << "Enter starting value x: ";
    cin >> pnew;
    // Main Loop
    for(i=0; i < N; i++){
        p = pnew;
        //Evaluate the function and its derivative
        f = 4*p - cos(p);
        dfdx= 4 + sin(p);
        // The Newton-Raphson step
        pnew = p - f/dfdx;
        // Check for convergence and quit if done
        if(abs(p-pnew) < tol){
            cout << "Root is " << pnew << " to within " << tol << "\n";
            return 0;
        }
    }
    // We reach this point only if the iteration failed to converge
    cerr << "Failed to converge after " << N << " iterations.\n";
    return 1;
}

Ответы [ 3 ]

3 голосов
/ 17 апреля 2019

1e-600 не представляется большинством реализаций double.std::cin не сможет преобразовать ваш ввод в double и перейдет в состояние отказа.Это означает, что, если вы не очистите состояние ошибки, любое будущее std::cin также автоматически завершится неудачей, не дожидаясь ввода пользователя.

С cppreference (начиная с c ++ 17):

Если извлечение не удалось, в значение записывается ноль и устанавливается failbit.Если извлечение приводит к тому, что значение слишком велико или слишком мало для соответствия значению, записывается std::numeric_limits<T>::max() или std::numeric_limits<T>::min() и устанавливается флаг failbit.

1 голос
/ 17 апреля 2019

Как уже упоминалось, 1e-600 не является действительным значением double. Тем не менее, это больше, чем за пределами диапазона. Вероятно, происходит то, что 1 сканируется в tol, а затем некоторая часть e-600 сканируется в pnew, и поэтому он сразу заканчивается, вместо того, чтобы запрашивать ввод для pnew.

0 голосов
/ 17 апреля 2019

Как сказал Франсуа, вы не можете превысить 2 ^ 64, когда работаете на 64-битной машине (с соответствующей ОС) и 2 ^ 32 на 32-битной машине, вы можете использовать SSE, которые представляют 4 32-байтовые данные, используемые для представления с плавающей запятой.В вашей программе функция завершается с ошибкой на каждой итерации и пропускает ваш тест с «если» и поэтому никогда не возвращается до завершения цикла.

...