Ошибка сегментации при рекурсивном вызове функции

#c #function #recursion #segmentation-fault

#c #функция #рекурсия #ошибка сегментации

Вопрос:

Моя задача — создать функцию, которая должна вычислять arcsin для моего ввода.

Я попытался отладить его с помощью xcode. Все работает нормально, пока arcsin(new); не будет вызван return . Тогда это segmentation fault: 11 . Я не уверен, почему, но точка останова во float arcsin(floatvalue){ ... } время выполнения второго цикла говорит мне, что значение с плавающей точкой старое и значение с плавающей NAN точкой.

 float arcsin(float value){

     float old = value;
     float new = value   (0.5 * ((value * value * value)/3));
     float accurate = 0.00001;  

     if ((new - old) < accurate){
        return new;
     }

     else{
        return arcsin(new);
     }
}


int function_arcsin(int sigdig, float value){

    value = arcsin(value);
    printf("%.10en",value);

    return 0;
}
  

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

1. new — это зарезервированное ключевое слово. Назовите это чем-то вроде float newval

2. @spicavigo: это C, а не C , так что все в порядке.

3. @spicavigo: вы уверены, что в C есть зарезервированное ключевое слово?

4. @rojcyk: пожалуйста, не могли бы вы добавить также, где вызывается эта функция? Находится внутри цикла? пожалуйста, добавьте некоторые подробности.

5. может быть, ваша формула неверна? он умирает при 174510-м вызове самого себя на моей машине.

Ответ №1:

Ошибка сегментации возникает, когда стек вызовов становится слишком большим, то есть слишком много уровней рекурсии.

В вашем случае это означает, что условие (new - old) < accurate всегда будет оцениваться как false — ну, может быть, не всегда, но достаточно раз, чтобы раздуть стек вызовов.

Тестируя ваш код, я вижу, что new (вероятно, неправильный выбор имени переменной) продолжает расти, пока не превысит пределы float . Вероятно, ваш алгоритм неверен.

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

1. Имя new тоже сбило меня с толку, потому что это ключевое слово в C , но действительно ли это считается плохим выбором в C? (В наши дни я не очень хорошо знаком с правилами стиля C).

2. @Steve314 вы никогда не знаете, когда захотите перенести или включить свой код на C , могли бы также выбрать well now вместо последующего рефакторинга, верно?

3. @Steve314 такие неинформативные имена переменных, как new или old , должны считаться плохим выбором на любом языке на самом деле

4. @LuchianGrigore Спасибо за отзыв, я буду работать над именами своих переменных. Я также изучу алгоритм. Еще раз, спасибо!

5. @maksenov — Я согласен с точкой зрения, но это очень маленькая функция, и в контексте смысл ясен. Даже значение value (менее конкретное, чем old или new ), вероятно, в порядке в контексте. Моя привычка для такого очевидного одиночного параметра, как этот, заключается в его вызове p . Я согласен, что полезно рано приобретать хорошие привычки, и, вероятно, легче избавиться от привычки к излишне длинным и явным именам, чем от привычки к слишком коротким и неясным именам, так что вы, вероятно, правы с этой точки зрения.

Ответ №2:

Я протестировал вашу программу и увидел, что цикл никогда не заканчивается:

 ((new - old) < accurate)  // never is true
  

если вы попытаетесь использовать числа> 0, достигнет nan за 10 итераций. С числами <0 продолжается тысячи раз и вызывает слишком глубокую рекурсию.

Ответ №3:

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

Преобразование в итеративную форму остановит ошибку segfault — но, если я не ошибаюсь, вместо этого создайте бесконечный цикл. Я бы не ожидал, что здесь будет проблемой рабочее рекурсивное решение, если только вы не тестировали со значениями, выходящими за пределы диапазона, с которым сходится аппроксимация — в этом случае мое первое предположение заключается в том, что входные данные в диапазоне от -pi до pi должны быть в порядке для любого применимого приближения arcsin.

Я не знаком с итеративной аппроксимацией arcsin, и мой google-fu еще не нашел ответа, но я подозреваю, что у вас неверный расчет в float new = ... строке.

Я нашел эту ссылку…

Ссылка

Это не так уж и полезно — ваш код не предполагает ни одного из описанных подходов.