#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 = ...
строке.
Я нашел эту ссылку…
Это не так уж и полезно — ваш код не предполагает ни одного из описанных подходов.