#c
Помогите пожалуйста написать на си. Вроде не сложно, но с математикой не идут задачи у меня.
Ответы
Ответ 1
Ну, смотрите. Для начала, ваша сумма неправильно раскрыта: для n = 0 имеем x^0 / 0!, то есть 1, а не x. Итак, начальное значение слагаемого 1. Чтобы перейти к новому слагаемому на i-ой итерации, надо домножить на x^2 и разделить на (2*i - 1) * (2 * i). Дальше ясно? Кстати, возведение в степень не нужно, если делать, так, как описано. С другой стороны, известно, что для лучшей точности вычислений необходимо начинать суммирование с наименьших по модулю чисел. То есть, считать лучше с конца. Для этого превратим один цикл в два: цикл от i = 0, x = 1 пока |x| >= eps увеличиваем i, x домножаем на x0 * x0 и делим на (2*i - 1) * (2 * i) цикл пока i >= 0 увеличиваем сумму на x, делим x на x0 * x0 и домножаем на (2*i - 1) * (2 * i), уменьшаем i Как правильно было подмечено в комментариях, вычисляя слагаемые дважды (один раз на пути вправо, и один раз на пути влево), мы теряем точность. Выход — запоминать вычисленные элементы (для этого неплохо бы иметь автоматически растущий контейнер, наподобие std::vector в C++), или делать три прохода: один для вычисления количества слагаемых, второй для вычисления самих слагаемых и запоминания их, третий для суммирования с конца. Вместо первого прохода можно, по идее, грубо оценить количество слагаемых по условию выхода (|x|^n/n! < eps <=> n ln |x| - ln n! < ln eps), применив формулу Стирлинга.Ответ 2
@VlaD, комментарии закончились, решил выложить пример на питоне # решение в лоб, суммируем слева направо def check(x = 0, eps = 0): sumPart = 1. curSum = 0 n = 1 while sumPart > eps: curSum += sumPart sumPart = sumPart * x * x / (n * (n + 1)) n += 2 return curSum # решение через рекурсию (по формуле @dzhioev), суммирование справа налево def calc(x = 0, eps = 0, n = 1, mulPart = 1): sumPart = 1. * (x * x) / (n * (n + 1)) stepSum = mulPart * sumPart if stepSum < eps: return 1 return 1 + sumPart * calc(x, eps, n + 2, stepSum) # хвостовая рекурсия, суммирование слева направо def tailLRSum(x = 0, eps = 0, n = 1, mulPart = 1, result = 1): currentSumPart = 1. * (x * x) / (n * (n + 1)) stepSum = mulPart * currentSumPart if stepSum < eps: return result return tailLRSum(x, eps, n + 2, stepSum, result + stepSum) # хвостовая рекурсия, суммирование справа налево (используем lambda) def tailRLSum(x = 0, eps = 0, n = 1, mulPart = 1, result = None): sumPart = 1. * (x * x) / (n * (n + 1)) stepSum = mulPart * sumPart if result == None: result = lambda value: value if stepSum < eps: return result(0) return tailRLSum(x, eps, n + 2, stepSum, lambda value: result(1 + sumPart * value)) Как видно - каждый метод дает свои результаты. Первые три - почти одни и те же, а вот последний ведет себя странно - точность у него не eps, а 10*eps. Т.е. если ему в проверке сделать if stepSum < eps * 0.1, то точность будет та, что нужна (вывод в скобках). И в данном случае (т.е. при eps * 0.1) точность будет выше, чем у остальных. Для себя понял, что ни фига не знаю как все работает внутри. Ведь по сути (по крайней мере для меня) второй и четвертый вариант должны отрабатывать одинаково - сначала вычисляются правые члены, затем добавляются левые. Аналогично и первый и второй - сначала вычисляются левые, затем правые члены. Но видно в каком-то месте (для меня неочевидном) происходит потеря точности. Причем где-то в последнем методе вообще что-то не хорошее творится... Насчет произвольной хвостовой рекурсии, дайте пример - посмотрю, а так ничего не скажу, т.к. не знаю. Есть кто-нить, кто может прокомментировать результаты?Ответ 3
Методом гнездовых процедур
Комментариев нет:
Отправить комментарий