Язык Си в примерах/Факториал: различия между версиями

Содержимое удалено Содержимое добавлено
Уточнения; оформление примеров; →‎Задания: отмена Special:Diff/109775 — см. [[{{TALKPAGENAME}}#Целесообразность вычисления]].
Уточнения; →‎Вариант «произвольный»: новый раздел.
Строка 64:
factorial_1 (int n, int p)
{
return (n < 2) ? p : factorialfactorial_1 (n - 1, p * n);
}
 
Строка 80:
<source lang="c">
static int
factorial (int n)
{
int r;
for (r = 1; n > 1; r *= (n--))
Строка 89 ⟶ 90 :
 
В отличие от [[#Реализация рекуррентной формулы |первого варианта]] (но аналогично варианту [[#Использование хвостовой рекурсии |с хвостовой рекурсией]]) в данном примере нам потребовалась дополнительная локальная переменная. В случае «нехвостовой» рекурсии — роль такой переменной фактически играет растущий ''стек возврата.'' Отметим, впрочем, что в данной конкретной задаче это не столь важно.
 
== Вариант «произвольный» ==
 
Стандарт требует поддержки реализацией [[Язык Си в примерах/Скалярные типы#Числовые типы |числовых типов]] разрядности 8, 16, 32 и 64 бит.<ref name="int-least" /> Несложно убедиться, однако, что уже 21! = 51 090 942 171 709 440 000 — что превышает предельные значения для 64-битового числа — как со знаком (9 223 372 036 854 775 807), так и без знака (18 446 744 073 709 551 615).
 
Если по каким-либо причинам требуется вычислить <em >точные</em> значения факториала для чисел от 21 и выше, следует использовать библиотеки операций с числами <em >произвольной</em> разрядности — как, например, [[w:en:GNU Multiple Precision Arithmetic Library |GNU MP.]]<ref name="gmp" />
 
{{Якорь |fact-imp.c}}
<source lang="c">
#include <stdio.h>
#include <gmp.h>
 
static void
factorial (long n, mpz_t r)
{
mpz_init_set_si (r, 1);
for (; n > 1; n--) {
mpz_mul_si (r, r, n);
}
}
 
int
main (void)
{
int n;
mpz_t r;
while (scanf ("%d", &n) == 1) {
factorial (n, r);
gmp_printf ("%Zd\n", r);
}
return 0;
}
</source>
 
== Задания ==
 
# Улучшите программы, добавив к ним диагностику ошибки во входных данных: если <var >n</var> &lt; 0, то программа должна ясно сообщать о неопределенности факториала для отрицательных чисел.
# Опытным путем определите максимальные значения аргумента и результата для «стандартных» программ выше. Исследуйте влияние на эти значения замены используемого в программах [[Язык Си в примерах/Скалярные типы#Числовые типы |числового типа]] <code >int</code> на <code >short</code>, <code >long</code> и <code >long long</code>. <strong >Обратите внимание</strong>, что при этом также потребуется соответственно изменить ''строку формата'' (первый аргумент) функции <code >printf</code>.
# Определите также максимальные значения аргумента и результата для программэтих вышепрограмм при использовании [[w:Число с плавающей запятой |чисел с плавающей запятой]] — [[Язык Си в примерах/Скалярные типы#Числовые типы |числовых типов]] <code >double</code>, <code >float</code>, <code >long double</code>.
 
== См. также ==
* [[Реализации алгоритмов/Факториал]] (на различных языках)
 
== Примечания ==
{{Примечания | refs =
<!-- Пожалуйста поддерживайте алфавитный порядок для name. Спасибо. -->
<ref name="gmp" >{{Cite web | title = The GNU MP Bignum Library | url = //gmplib.org/ | lang = en | accessdate = 2015-04-04}}</ref>
<ref name="int-least" >{{Cite web | title = 7.20.1.2 Minimum-width integer types | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=308 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
}}
 
{{BookCat}}