Факториал
Вычисление факториала чисел от 0 до 16. Факториал n! = 1 * 2 * … * n.
Вывод программы должен выглядеть следующим образом:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
Отметим, что данный пример может быть реализован несколькими способами:
- через рекурсивное определение факториала n! = n * (n-1)!
- перемножением чисел от 1 до n в цикле.
- использованием встроенной функции языка.
Пример для версий Lua 5.0 Lua 5.1
Используется рекурсивное определение факториала.
function factorial(n)
if (n == 0) then
return 1
else
return n * factorial(n - 1)
end
end
for n = 0, 16 do
io.write(n, "! = ", factorial(n), "\n")
end
Пример для версий Free Pascal 1.0.6 Free Pascal 2.0.4 Free Pascal 2.2.0 Free Pascal 2.2.4 Turbo Pascal 4.0 Turbo Pascal 5.0 Turbo Pascal 5.5 Turbo Pascal 6.0 Turbo Pascal 7.0
Используется рекурсивное определение факториала.
Этот пример работает как в Turbo Pascal, так и в Free Pascal, но с несколько разным результатом. В обеих реализациях возникает арифметическое переполнение при вычислении факториалов 13-16, но Free Pascal сообщает об ошибке:
13! = Runtime error 215 at $004013C7
$004013C7
$00401449
$004063E0
в то время как Turbo Pascal не обнаруживает ошибку и просто выводит неправильные значения:
13! = 1932053504
14! = 1278945280
15! = 2004310016
16! = 2004189184
Следует отметить, что в версиях Turbo Pascal 3.0 и младше этот пример не работает из-за отсутствия типа данных longint.
program factorial;
function fact(n: integer): longint;
begin
if (n = 0) then
fact := 1
else
fact := n * fact(n - 1);
end;
var
n: integer;
begin
for n := 0 to 16 do
writeln(n, '! = ', fact(n));
end.
Пример для версий GHC 6.10.4 GHC 6.6.1
Используется рекурсивное определение факториала. Пример состоит из трех частей:
-
определение функции
factorial, принимающей на вход один аргумент типаInteger(целое число неограниченной точности) и имеющей выход того же типа. Функция определяется рекурсивно, тип параметров задан в явном виде, чтобы избежать неоднозначности их определения. -
определение функции
line, которая выводит на печать число и его факториал в нужном формате. Использование командыprintfаналогично языку C++. -
собственно вывод чисел и их факториалов. Для этого командой
[0..16]создается список чисел от 0 до 16, включительно. Функция двух аргументовmapприменяет первый аргумент (функциюline) к каждому элементу второго аргумента (списка[0..16]) и в результате создает список так называемых действий вывода (являющихся в Haskell обычными значениями). Для того, чтобы объединить эти действия в одно, используется командаsequence_, которая, будучи применена к списку действий, выполняет первое действие из списка и затем рекурсивно применяет себя к хвосту списка.
module Main where
import Text.Printf
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)
line x = printf "%d! = %d\n" x $ factorial x
main = sequence_ $ map line [0..16]
Пример для версий Bash 3.0 Bash 3.2.39
Используется рекурсивное определение факториала.
#!/bin/bash
factorial ()
{
local num=$1;
if [ $num = 0 ]; then
echo 1
return ;
fi;
echo $(( $num * $(factorial $(( $num - 1 )) ) ))
}
for ((n = 0; n <= 16; n++))
do
echo "$n! = " $(factorial $(($n)))
done
Пример для версий GCC 3 GCC 4
Используется рекурсивное определение факториала.
#include <stdio.h>
unsigned long long factorial(unsigned long long n)
{
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
int main(void)
{
int n;
for (n = 0; n <= 16; n++) {
printf("%i! = %lld\n", n, factorial(n));
}
return 0;
}
Пример для версий Borland C++ Builder 6 g++ 4.x
Используется рекурсивное определение факториала.
#include <iostream>
unsigned long long factorial(unsigned long long n)
{
if (n == 0)
return 1;
else
return n * factorial (n - 1);
}
int main(void)
{
for (int n = 0; n <= 16; n++)
std::cout << n << "! = " << factorial(n) << std::endl;
return 0;
}
Пример для версий MinGW
Используется рекурсивное определение факториала.
#include <stdio.h>
unsigned long long factorial(unsigned long long n)
{
if (n == 0) {
return 1;
} else {
return n * factorial (n - 1);
}
}
int main(void)
{
int n;
for (n = 0; n <= 16; n++) {
printf("%i! = %I64u\n", n, factorial(n));
}
return 0;
}
Пример для версий .NET 1.0 .NET 2.0 Mono 1.2.4
Используется рекурсивное определение факториала.
using System;
namespace factorial_csharp
{
class MainClass
{
public static long factorial(long n)
{
if (n == 0)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
public static void Main(string[] args)
{
for (int n = 0; n <= 16; n++)
{
Console.WriteLine("{0:D}! = {1:D}", n, factorial(n));
}
}
}
}
Пример для версий GNU bc 1.06
Используется рекурсивное определение факториала.
#! /usr/bin/env bc
define factorial(n) {
if (n == 0) return(1);
return(n * factorial(n - 1));
}
for (n = 0; n <= 16; n++) {
print n; "! = "; factorial(n);
}
quit
Пример для версий ARIBAS 1.53
Используется рекурсивное определение факториала функцией fac, т.к. имя factorial зарезервировано для встроенной функции вычисления факториала. В ARIBAS по умолчанию используется тип данных integer.
group(0) при выводе служит для отмены использования знака подчеркивания для разделения групп цифр.
function fac(n);
begin
if (n = 0) then
return(1);
end;
return(n * factorial(n - 1));
end;
function fac0_16();
var n;
begin
for n := 0 to 16 do
writeln(n, "! = ", fac(n): group(0));
end;
end;
fac0_16().
Пример для версий ARIBAS 1.53
Используется встроенная функция factorial. В ARIBAS по умолчанию используется тип данных integer.
group(0) при выводе служит для отмены использования знака подчеркивания для разделения групп цифр.
function fac0_16();
var n;
begin
for n := 0 to 16 do
writeln(n, "! = ", factorial(n): group(0));
end;
end;
fac0_16().
Пример для версий Nesla 0.6.0 Nesla 0.8.0
Для факториала 13-16 из-за арифметического переполнения возвращается nan (not a number). В результате вывод программы имеет следующий вид:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = nan
14! = nan
15! = nan
16! = nan
#!/usr/bin/nesla
function factorial(n)
{
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
for (n = 0; n <= 16; n++) {
print(n, "! = ", factorial(n), "\n");
}
Пример для версий Seed7 2007-06-07 Seed7 2007-06-24
Используется рекурсивное определение факториала.
$ include "seed7_05.s7i";
include "bigint.s7i";
const func bigInteger: factorial (in var bigInteger: n) is func
result
var bigInteger: result is 1_;
begin
if n = 0_ then
result := 1_;
else
result := n * factorial(n - 1_);
end if;
end func;
const proc: main is func
local
var integer: n is 0;
begin
for n range 0 to 16 do
write(n);
write("! = ");
write(factorial(bigInteger conv n));
writeln;
end for;
end func;
Пример для версий Seed7 2007-06-07 Seed7 2007-06-24
Используется встроенная функция !n, определенная только для типа данных integer. 13! больше максимально возможного значения этого типа, и попытка его вычисления вызывает арифметическое переполнение. В результате вывод программы имеет следующий вид:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! =
* Uncaught EXCEPTION NUMERIC_ERROR raised with
{! integer <80ba990>: <SYMBOLOBJECT> 0 }
{! (in integer <80ba990> param) } at factorial-builtin.sd7(10)
main no POSINFO
$ include "seed7_05.s7i";
const proc: main is func
local
var integer: n is 0;
begin
for n range 0 to 16 do
write(n);
write("! = ");
write(!n);
writeln;
end for;
end func;
Пример для версий Ruby 1.8.5
Используется рекурсивное определение факториала.
#! /usr/bin/env ruby
def factorial(n)
if n == 0
1
else
n * factorial(n - 1)
end
end
0.upto(16) do |n|
print(n, "! = ", factorial(n), "\n")
end
Пример для версий boo 0.7.6.2237
Используется рекурсивное определение факториала. Из-за того, что функция factorial вызывается рекурсивно, для нее необходимо объявление типа возвращаемого значения.
def factorial(n as ulong) as ulong:
if n == 0:
return 1
else:
return n * factorial(n - 1)
for n in range(0, 17):
print("${n}! = ${factorial(n)}")
Пример для версий GHC 6.6.1
Функция fac определена как произведение чисел от 1 до n через встроенную функцию языка product.
module Main where
import Text.Printf
fac n = product [1..n]
main = sequence_ $ map (\x -> printf "%d! = %d\n" x $ fac x) [0..16]
Пример для версий Scala 2.5.1-final Scala 2.7.7-final
Используется рекурсивное определение факториала.
object Factorial {
def factorial(n: Int): Long =
if (n == 0) 1
else n * factorial(n - 1)
def main(args: Array[String]) {
for {i <- List.range(0, 17)}
yield { println(i + "! = " + factorial(i)) }
}
}
Пример для версий F# 1.9.2.9
Используется сопоставление по образцу с последующим рекурсивным вызовом. Ключевое слово let задаёт новое определение — в данном случае функцию fac. rec означает, что определение будет рекурсивным. Сопоставление по образцу определяется ключевым словом match.
let rec fac n = match n with
| 0 -> 1
| _ -> n * fac(n - 1)
do printf "10! = %d" (fac 10)
Пример для версий Toka 1.2
Для факториалов 13-16 из-за арифметического переполнения возвращается неверное значение. Также не получилось убрать пробел между аргументом и знаком “!”. В результате вывод программы имеет следующий вид:
0 ! = 0
1 ! = 1
2 ! = 2
3 ! = 6
4 ! = 24
5 ! = 120
6 ! = 720
7 ! = 5040
8 ! = 40320
9 ! = 362880
10 ! = 3628800
11 ! = 39916800
12 ! = 479001600
13 ! = 1932053504
14 ! = 1278945280
15 ! = 2004310016
16 ! = 2004189184
#! /usr/bin/toka
[ dup 1 > [ dup 1 - recurse * ] ifTrue ] is factorial
0 17 [ i . i ." ! = " i factorial . cr ] countedLoop
bye
Пример для версий BlackBox Component Builder 1.5
Используется рекурсивное определение факториала.
О том как запустить программу на выполнение — см. <a href=”http://www.inr.ac.ru/~info21/blackbox/start/welcome.html”>Как запустить Блэкбокс и выполнить первую программу</a>.
MODULE Example;
IMPORT StdLog;
PROCEDURE factorial(n: INTEGER): LONGINT;
BEGIN
IF n = 0 THEN
RETURN 1;
ELSE
RETURN n * factorial(n-1)
END;
END factorial;
PROCEDURE Do*;
VAR
n: INTEGER;
BEGIN
FOR n := 0 TO 16 DO
StdLog.Int(n);
StdLog.String('! = ');
StdLog.Int(factorial(n));
StdLog.Ln;
END;
END Do;
END Example.
Пример для версий gpcp 1.3.4-JVM gpcp 1.3.4-NET 1.1 gpcp 1.3.9-NET
Используется рекурсивное определение факториала.
MODULE Example;
IMPORT CPmain, RTS;
VAR
n: INTEGER;
s: ARRAY 15 OF CHAR;
PROCEDURE factorial*(n: INTEGER): LONGINT;
BEGIN
IF n = 0 THEN
RETURN 1;
ELSE
RETURN n * factorial(n - 1)
END;
END factorial;
BEGIN
FOR n := 0 TO 16 DO
Console.WriteInt(n, 2);
Console.WriteString('! = ');
RTS.LongToStr(factorial(n), s);
Console.WriteString(s);
Console.WriteLn;
END;
END Example.
Пример для версий Euphoria 3.1.1
Используется рекурсивное определение факториала.
function factorial(integer n)
if n = 0 then
return 1
else
return n*factorial(n-1)
end if
end function
for n = 0 to 16 do
printf(1,"%d! = %d\n",{n,factorial(n)})
end for
Пример для версий Oracle 10g SQL
SQL не поддерживает циклы, рекурсии или пользовательские функции. Данный пример демонстрирует возможный обходной путь, использующий:
-
псевдостолбец
levelдля создания псевдотаблицt1иt2, содержащих числа от 1 до 16, -
агрегатную функцию
sum, позволяющую суммировать элементы множества без явного использования цикла, -
и математические функции
lnиexp, позволяющие заменить произведение (необходимое для вычисления факториала) на сумму (предоставляемую SQL).
Строка “0! = 1” не войдет в набор строк, полученный в результате, т.к. попытка вычислить ln(0) приводит к исключению.
select t2.n || '! = ' || round(exp(sum(ln(t1.n))))
from
( select level n
from dual
connect by level <= 16) t1,
( select level n
from dual
connect by level <= 16) t2
where t1.n<=t2.n
group by t2.n
Пример для версий PHP 5.2.4
<?php
function factorial($n)
{
if ($n == 0) {
return 1;
} else {
return $n * factorial($n - 1);
}
}
for ($n = 0; $n <= 16; $n++) {
echo($n . "! = " . factorial($n) . "\n");
}
?>
Пример для версий Corman Common Lisp 3.0
Этот пример использует рекурсивное определение факториала, естественное для Lisp. Демонстрирует следующие особенности языка:
-
математические операторы:
(- n 1)— это префиксная запись, эквивалентная инфиксной записиn-1; -
операторы сравнения:
(= n 0)возвращает T, если n равно нулю, иnil(используется как false) в противном случае; -
условный оператор
if: выражения в Lisp определяются по скобкам и могут записыватся в несколько строк; -
определение функции с использованием
defun; -
макрос Common Lisp
loop; -
спецификации формата вывода в
format:~Dсоответствует целому числу, а~%— концу строки.
(defun factorial (n)
(if (= n 0)
1
(* n (factorial (- n 1)))
)
)
(loop for i from 0 to 16
do (format t "~D! = ~D~%" i (factorial i))
)
Пример для версий Borland C++ Builder 6 Microsoft Visual C++ 6
Используется рекурсивное определение факториала. Реализация отличается от альтернативной использованием типа __int64 вместо unsigned long long и функции вывода на печать printf вместо std::cout <<.
#include "stdio.h"
__int64 factorial(__int64 n)
{
return (n==0 ? 1 : n*factorial(n-1));
}
int main(int argc, char* argv[])
{
for (int n=0; n<=16; n++)
printf("%d! = %I64d\n",n,factorial(n));
return 0;
}
Пример для версий gcj 3.4.5 Sun Java 6
Используется рекурсивное определение факториала. Для хранения больших чисел использован элементарный тип данных long, позволяющий хранить числа от -263 до 263-1.
public class Factorial {
static long factorial(int n)
{
return ( n==0 ? 1 : n*factorial(n-1) );
}
public static void main(String[] args)
{
for (int n=0; n<=16; n++)
System.out.println(n+"! = "+factorial(n));
}
}
Пример для версий gcj 3.4.5 Sun Java 6
Используется итеративное вычисление факториала. Для хранения больших чисел используется встроенный класс BigInteger, позволяющий обрабатывать сколь угодно большие числа ценой увеличения времени обработки.
import java.math.BigInteger;
public class Factorial {
public static void main(String[] args)
{
BigInteger f = new BigInteger("1");
System.out.println("0! = " + f.toString());
for (int n=1; n<=16; n++)
{ f = f.multiply(new BigInteger(""+n));
System.out.println( n + "! = " + f.toString());
}
}
}
Пример для версий Microsoft Visual Basic 6
Используется рекурсивное определение факториала. Из-за арифметического переполнения при вычислении факториалов 13-16 вывод программы заканчивается на строке “12! = …”, после чего в отдельном не-консольном окне выдается сообщение “Run-time error ‘6’: Overflow”.
Option Explicit
Declare Function AllocConsole Lib "kernel32" () As Long
Declare Function FreeConsole Lib "kernel32" () As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" _
(ByVal hConsoleOutput As Long, lpBuffer As Any, ByVal _
nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, _
lpReserved As Any) As Long
Declare Function Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) As Long
Public Function Factorial(ByVal n As Integer) As Long
If (n = 0) Then
Factorial = 1
Else
Factorial = n * Factorial(n - 1)
End If
End Function
Private Sub Main()
'create a console instance
AllocConsole
'get handle of console output
Dim hOut As Long
hOut = GetStdHandle(-11&)
'output string to console output
Dim s As String
Dim i As Integer
For i = 0 To 16 Step 1
s = i & "! = " & Factorial(i) & vbCrLf
WriteConsole hOut, ByVal s, Len(s), vbNull
Next i
'make a pause to look at the output
Sleep 2000
'close the handle and destroy the console
CloseHandle hOut
FreeConsole
End Sub
Пример для версий Microsoft Visual Basic 6
Используется итеративное определение факториала.
Option Explicit
Declare Function AllocConsole Lib "kernel32" () As Long
Declare Function FreeConsole Lib "kernel32" () As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" _
(ByVal hConsoleOutput As Long, lpBuffer As Any, ByVal _
nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, _
lpReserved As Any) As Long
Declare Function Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) As Long
Private Sub Main()
'create a console instance
AllocConsole
'get handle of console output
Dim hOut As Long
hOut = GetStdHandle(-11&)
'output string to console output
Dim s As String
Dim i As Integer
Dim f As Long
f = 1
s = "0! = 1" & vbCrLf
WriteConsole hOut, ByVal s, Len(s), vbNull
For i = 1 To 16 Step 1
f = f * i
s = i & "! = " & f & vbCrLf
WriteConsole hOut, ByVal s, Len(s), vbNull
Next i
'make a pause to look at the output
Sleep 2000
'close the handle and destroy the console
CloseHandle hOut
FreeConsole
End Sub
Пример для версий QBasic 1.1
Используется итеративное определение факториала. Из-за арифметического переполнения при вычислении факториалов 13-16 вывод программы заканчивается на строке “12! = …”, после чего интерпретатор сообщает о переполнении. Кроме того, команда PRINT по умолчанию выводит по одному пробелу перед числом и после него.
DIM f AS LONG
f = 1
PRINT " 0 ! ="; f
FOR i = 1 TO 16:
f = f * i:
PRINT i; "! ="; f
NEXT i
END
Пример для версий QBasic 1.1
По умолчанию для вычислений используется вещественный тип данных. Вывод программы имеет следующий вид:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 3.99168Е+07
12! = 4.790016Е+08
13! = 6.227021Е+09
14! = 8.717829Е+10
15! = 1.307674Е+12
16! = 2.092279Е+13
DECLARE FUNCTION factorial (n)
FOR i = 0 TO 16:
PRINT STR$(i) + "! =" + STR$(factorial(i))
NEXT i
END
FUNCTION factorial (n)
IF n = 0 THEN
factorial = 1
ELSE
factorial = n * factorial(n - 1)
END IF
END FUNCTION
Пример для версий Müller's Brainfuck 2.0
В примере используется итеративное определение факториала: последний вычисленный факториал хранится в ячейке-переменной c6 и на каждом шагу умножается на очередное число, хранящееся в c5. Низкоуровневое описание приведено в комментариях к коду, запись “cXvY” означает, что после выволнения команд в строке указатель данных находится в ячейке X, и значение в этой ячейке равно Y.
Классический интерпретатор Brainfuck использует переменные типа byte для хранения значений в ячейках памяти, и уже 6! вызовет ошибку переполнения. Написание длинной арифметики на Brainfuck — задача достаточно трудоемкая, поэтому в примере предполагается, что в ячейках памяти могут храниться числа типа integer.
+++++++++++++++++++++++++++++++++ c1v33 : ASCII code of !
>++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++ c2v61 : ASCII code of =
>++++++++++ c3v10 : ASCII code of EOL
>+++++++ c4v7 : quantity of numbers to be calculated
> c5v0 : current number (one digit)
>+ c6v1 : current value of factorial (up to three digits)
<< c4 : loop counter
[ block : loop to print one line and calculate next
>++++++++++++++++++++++++++++++++++++++++++++++++. c5 : print current number
------------------------------------------------ c5 : back from ASCII to number
<<<<.-.>.<.+ c1 : print !_=_
>>>>> block : print c6 (preserve it)
> c7v0 : service zero
>++++++++++ c8v10 : divizor
<< c6 : back to dividend
[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<] c6v0 : divmod algo borrowed from esolangs; results in 0 n d_n%d n%d n/d
>[<+>-] c6 : move dividend back to c6 and clear c7
>[-] c8v0 : clear c8
>> block : c10 can have two digits; divide it by ten again
>++++++++++ c11v10: divizor
< c10 : back to dividend
[->-[>+>>]>[+[-<+>]>+>>]<<<<<] c10v0 : another divmod algo borrowed from esolangs; results in 0 d_n%d n%d n/d
>[-] c11v0 : clear c11
>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]c13v0 : print nonzero n/d (first digit) and clear c13
<[++++++++++++++++++++++++++++++++++++++++++++++++.[-]] c12v0 : print nonzero n%d (second digit) and clear c12
<<<++++++++++++++++++++++++++++++++++++++++++++++++.[-] c9v0 : print any n%d (last digit) and clear c9
<<<<<<. c3 : EOL
>>+ c5 : increment current number
block : multiply c6 by c5 (don't preserve c6)
>[>>+<<-] c6v0 : move c6 to c8
>> c8v0 : repeat c8 times
[
<<<[>+>+<<-] c5v0 : move c5 to c6 and c7
>>[<<+>>-] c7v0 : move c7 back to c5
>-
]
<<<<- c4 : decrement loop counter
]
Пример для версий Microsoft SQL Server 2005
Используется рекурсивное определение факториала, реализованное через рекурсивный запрос. Каждая строка запроса содержит два числовых поля — n и n!, и каждая следующая строка вычисляется с использованием данных из предыдущей.
with factorial(n, f) as
(
select 0, 1
union all
select n+1, f*(n+1) from factorial where n<16
)
select cast(n as varchar)+'! = '+cast(f as varchar)
from factorial
Пример для версий Icon Version 9
хакерский укороченный вариант
procedure main ()
local i, j
every write (i := 1 to 20, "! = ", { j := 1; every j *:= 1 to i; j })
end
Пример для версий Icon Version 9
развёрнутый нехакерский вариант
procedure factorial (n)
if n = 0 then
return 1
else if n >= 0 then
return n * factorial (n - 1)
end
procedure main ()
local i
every i := 1 to 20 do
write (i, "! = ", factorial (i))
end
Пример для версий Interactive FP
Этот пример определяет четыре функции — две по необходимости, и две для читабельности. Все они принимают на вход скалярные значения; seq возвращает последовательность скаляров, остальные три — скаляры.
-
zeroпроверяет, равен ли ее аргумент нулю; -
decуменьшает аргумент на единицу; -
seqвозвращает<0>, если ее аргументxравен нулю, и результат примененияseqк(x-1)с присоединенным справаxиначе (если мы развернем это рекурсивное определение, мы получим просто последовательность<0 1 … x>) . -
factorialвозвращает 1, если ее аргументxравен нулю, и результат примененияfactorialк(x-1), умноженный наx, иначе.
Последняя строка примера применяет factorial к каждому элементу последовательности, полученной применением seq к входному параметру — 16. Следует отметить, что все матеметические операции возвращают числа с плавающей запятой, поэтому результат выполнения программы будет иметь следующий вид:
< 1 1.0 2.0 6.0 24.0 120.0 720.0 5040.0 40320.0 362880.0 3628800.0 3.99168E7 4.790016E8 6.2270208E9 8.7178289E10 1.30767428E12 2.09227885E13 >
{ zero ( = @ [id, %0] ) }
{ dec ( - @ [id, %1] ) }
{ seq ( zero -> %<0> ; apndr @ [ seq @ dec , id ] ) }
{ factorial ( zero -> %1 ; * @ [id, factorial @ dec ] ) }
&factorial @ seq:16
Пример для версий Visual Prolog 7.2
Для запуска создайте новый проект с UI Strategy “Console” и замените содержимое файлов main.cl и main.pro приведенным кодом.
В main.cl добавлена одна строка factorial : (integer N, integer F) procedure (i,o)., которая определяет бинарный предикат factorial с известным первым и неизвестным вторым аргументами. Ключевое слово procedure описывает поведение предиката, указывая, что его вычисление всегда будет успешным и будет найдено ровно одно решение, так что откаты не понадобятся.
В main.pro находится собственно определение нового предиката. Для каждого его вызова есть два возможных соответствия — с нулевым или произвольным первым аргументом. Visual Prolog перебирает формулы в порядке их появления в коде, так что если первый аргумент равен нулю, проверка начинается с первой формулы factorial(0,F). Первое правило формулы — !, так называемое отсечение, использование которого предотвращает откат ко второй формуле и таким образом обеспечивает наличие ровно одного решения предиката. После этого переменная F, содержащая решение предиката, устанавливается в 1 и выводится на печать. Вторая формула factorial(N,F) рекурсивно вычисляет F1 как факториал N-1, устанавливает решение предиката равным N*F1 и выводит его на печать. Наконец, stdio::nl печатает новую строку.
При выполнении основной программы предикат factorial выполняется ровно один раз, для N=12. С каждым вызовом рекурсии N уменьшается на единицу, пока не становится равным нулю. После этого значения факториалов возвращаются и выводятся на печать в порядке возрастания. Программа обрабатывает только факториалы до 12!, т.к. попытка вычисления 13! вызывает ошибку переполнения целочисленного типа.
% main.cl
class main
open core
predicates
classInfo : core::classInfo.
factorial : (integer N, integer F) procedure (i,o).
predicates
run : core::runnable.
end class main
% main.pro
implement main
open core
constants
className = "main".
classVersion = "".
clauses
classInfo(className, classVersion).
factorial(0,F) :-
!,
F = 1,
stdio::write("0! = 1"),
stdio::nl.
factorial(N,F) :-
factorial(N-1,F1),
F = N*F1,
stdio::write(N, "! = ", F),
stdio::nl.
clauses
run():-
console::init(),
factorial(12,F),
programControl::sleep(1000),
succeed().
end implement main
goal
mainExe::run(main::run).
Пример для версий Oracle 10g SQL
Этот пример демонстрирует использование оператора model, доступного начиная с версии Oracle 10g и позволяющего обработку строк запроса как элементов массива. Каждая строка содержит два поля — номер строки n и его факториал f.
select n || '! = ' || f factorial
from dual
model
return all rows
dimension by ( 0 d )
measures ( 0 f, 1 n )
rules iterate (17)
( f[iteration_number] = decode(iteration_number, 0, 1, f[iteration_number-1]*iteration_number),
n[iteration_number] = iteration_number
);
Пример для версий MySQL 5
Замените TABLE на любую таблицу, к которой есть доступ, например, mysql.help_topic.
select concat(cast(t2.n as char), "! = ", cast(exp(sum(log(t1.n))) as char))
from
( select @i := @i+1 AS n
from TABLE, (select @i := 0) as sel1
limit 16 ) t1,
( select @j := @j+1 AS n
from TABLE, (select @j := 0) as sel1
limit 16 ) t2
where t1.n <= t2.n
group by t2.n
Пример для версий VB.NET 9 (2008)
Используется рекурсивное определение факториала.
Module Module1
Function Factorial(ByVal n As Integer) As Long
If n = 0 Then
Return 1
Else
Return n * Factorial(n - 1)
End If
End Function
Sub Main()
For i As Integer = 0 To 16
Console.WriteLine(i & "! = " & Factorial(i))
Next
End Sub
End Module
Пример для версий Oracle 10g SQL
Этот пример демонстрирует итеративное вычисление факториала средствами PL/SQL.
declare
n number := 0;
f number := 1;
begin
while (n<=16)
loop
dbms_output.put_line(n || '! = ' || f);
n := n+1;
f := f*n;
end loop;
end;
Пример для версий Free Pascal 2.0.4 Turbo Pascal 1.0 Turbo Pascal 2.0 Turbo Pascal 3.0 Turbo Pascal 4.0 Turbo Pascal 5.0 Turbo Pascal 5.5 Turbo Pascal 6.0 Turbo Pascal 7.0
Этот пример работает точно так же, как основной рекурсивный пример для Pascal, но использует тип real для хранения значений факториала. Команда writeln(f:-1:0) выводит дробное число f с 0 цифр после десятичной запятой и выравнивает его по левому краю.
program factorial;
function fact(n: integer): real;
begin
if (n = 0) then
fact := 1
else
fact := n * fact(n - 1);
end;
var
n: integer;
begin
for n := 0 to 16 do
writeln(n, '! = ', fact(n):-1:0);
end.
Пример для версий gfortran 4.5.0 Intel Visual Fortran 11.1
Используется итеративное определение факториала. Спецификации формата I и A используются для вывода чисел в десятичном формате и строк, соответственно. При вычислении факториалов 13-16 возникает арифметическое переполнение, не вызывающее ошибку, поэтому выводятся неправильные значения:
13! = 1932053504
14! = 1278945280
15! = 2004310016
16! = 2004189184
program Factorial
integer :: f,n
f = 1
n = 0
do
print '(I2, A, I10)', n, "! = ", f
n = n + 1
f = f * n
if (n==17) then
exit
end if
end do
end program Factorial
Пример для версий Poplog 15.5 (Prolog)
Этот пример состоит из двух частей — первую часть кода следует сохранить в файле fact.pl, расположенном в рабочем каталоге Poplog, а вторую — ввести вручную в интерактивном режиме.
[-fact]. загружает базу фактов и правил из этого файла в текущую сессию Poplog (и выводит сообщение fact reconsulted, чтобы обозначить успешность загрузки). Запрос fact(16,X). пытается найти значение X, при котором этот предикат будет оценен как истинный. Вывод, требующийся в примере, будет побочным эффектом оценивания запроса, а основным результатом будет X = 20922789888000 ?. Это означает, что если вы недовольны такой привязкой переменных, вы можете отказаться от нее (введя ; ), и будет продолжен поиск лучшей привязки.
% fact.pl
fact(X, F) :-
( X=0, F=1;
Y is X-1, fact(Y, Z), F is X*Z),
write(X), write('! = '), write(F), nl.
% interactive
[-fact].
fact(16,X).
Пример для версий Poplog 15.5 (POP-11)
Используется рекурсивное определение факториала. factorial(n) вычисляет значение n!, в то время как loop(n) используется в качестве цикла для перебора факториалов чисел от 0 до n, включительно. >< — оператор конкатенации. Следует отметить, что loop не возвращает значения.
Текст примера может быть набран в интерактивном режиме. Иначе можно сохранить определения функций в файл fact.p, находящийся в рабочем каталоге Poplog, и в интерактивном режиме ввести load fact.p для загрузки содержимого файла.
define factorial(n);
if n == 0
then 1
else n * factorial(n - 1)
endif
enddefine;
define loop(n);
if n>0
then loop(n-1)
endif;
n >< '! = ' >< factorial(n) =>
enddefine;
loop(16) =>
Пример для версий SpiderMonkey (Firefox 3.5)
Используется рекурсивное определение факториала. Пример предназначен для запуска из веб-браузера. Команда document.write очищает текущую веб-страницу.
function factorial(n)
{ if (n == 0)
return 1;
else
return n * factorial(n-1);
}
var i;
document.clear();
for (i = 0; i <= 16; i++)
document.write(i + "! = " + factorial(i) + "<br />");
Пример для версий Corman Common Lisp 3.0
Внутренний цикл с операцией collect создает список чисел от 1 до n, после чего к нему применяется операция *.
(loop for n from 0 to 16
do (format t "~D! = ~D~%" n
(apply '* (loop for i from 1 to n
collect i)) ) )
Пример для версий Furry Paws
Этот пример работает точно так же, как пример для Interactive FP, за исключением отсутствия определения функции zero, являющейся встроенной. Следует отметить, что здесь все операции выполняются в пределах стандартного целочисленного типа, и 13! вызывает ошибку переполнения, поэтому программа может быть вызвана только для факториалов до 12!. show — альтернативный способ вывода информации.
dec = sub.[id, ~1]
seq = zero -> [id] ; cat.[seq.dec, [id]]
factorial = zero -> ~1 ; mul.[id, factorial.dec]
main = show.(return @factorial.(seq.~12))
Пример для версий gnat 3.4.5
В этом примере используется рекурсивное определение факториала.
Следует отметить, что для вывода на печать текста, целых и длинных целых чисел используются разные пакеты. Команда put в общем случае принимает несколько аргументов, изменяющих формат вывода: Item — это число, которое выводится на печать, Width — количество позиций, которые следует использовать при выводе, Fore и Aft — количества десятичных цифр, которые следует вывести до и после запятой и т.д. Если передается только один аргумент, он считается значением Item. Установив Width равным 1 или другому числу, меньшему, чем количество цифр в выводимом числе, можно вывести его без пробелов в начале (что является умолчательным способом для языка Ada).
Кроме того, отметим, что Ada не поддерживает неявные преобразования типов, так что для вычисления N*Fact(N-1) сначала следует явно преобразовать N к типу Long_Long_Integer.
with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Long_Long_Integer_Text_IO;
procedure Factorial is
begin
declare
function Fact (N: Integer) return Long_Long_Integer is
begin
if N=0 then
return 1;
else
return Long_Long_Integer(N)*Fact(N-1);
end if;
end Fact;
i: Integer := 0;
begin
loop
Ada.Integer_Text_IO.Put (Item => i, Width => 1);
Ada.Text_IO.Put ("! = ");
Ada.Long_Long_Integer_Text_IO.Put (Item => Fact(i), Width => 1);
Ada.Text_IO.New_Line;
i := i + 1;
exit when i=17;
end loop;
end;
end Factorial;
Пример для версий UCBLogo 6.0
Используется рекурсивное определение факториала. В примере определяются две функции — factorial, вычисляющая N!, и print_factorial, которая выводит факториалы чисел от i до N.
to factorial :N
ifelse :N = 0 [output 1] [output :N * factorial :N - 1]
end
to print_factorial :i :N
repeat :N - :i + 1 [(print :i [! =] factorial :i)
make "i sum :i 1]
end
print_factorial 0 16
Пример для версий Scala 2.7.7-final
Используется итеративное определение факториала.
object Factorial {
def main(args: Array[String]) {
var f = BigInt(1)
format("0! = %s\n", f)
for {i <- 1 to 16} {
f *= i;
format("%s! = %s\n", i, f)
}
}
}
Пример для версий gawk 3.1.6 mawk 1.3.3
Используется итеративное определение факториала. Отдельные команды в пределах блока могут разделятся точками с запятой или переносами строк.
BEGIN {
f = 1
print "0! = " f
for (i=1; i<17; i++) {
f *= i
print i "! = " f
}
}
Пример для версий S-lang 2.2.2
В примере используется рекурсивное определение факториала. Для создания рекурсивной функции в S-lang, следует сначала объявить ее (без списка параметров или реализации) и только потом собственно определить ее, указав параметры и тело функции.
В примере показано использование суффикса $. Строковая константа может оканчиваться суффиксом, который определяет то, как она обрабатывается. Суффикс $ означает, что перед использованием строки в ней будет произведена подстановка имен переменных: каждое имя переменной, предваренное префиксом $, будет заменено на значение переменной. При этом имя переменной должно быть отделено от следующих символов строки пробелом либо заключено в фигурные скобки.
Отметим, что типом данных по умолчанию является integer, поэтому в данном примере возникает ошибка переполнения при вычислении 13!.
define factorial ();
define factorial (n)
{ if (n==0) return 1;
return n * factorial (n-1);
};
for (i=0; i<17; i++)
{ f = factorial (i);
message ("${i}! = ${f}"$);
};
Пример для версий S-lang 2.2.2
Этот пример демонстрирует операции над массивами в S-lang. [1:i] создает список чисел от 1 до i; следует отметить, что для операций над массивами типом данных по умолчанию является double, даже если сами числа целые. Встроенная функция prod (с версии 2.1) вычисляет произведение элементов массива-аргумента. Встроенная функция sprintf предоставляет вывод в стиле языка C, шаблон %.0f печатает число с плавающей запятой с нулем цифр после запятой.
for (i=0; i<17; i++)
sprintf ("%d! = %.0f", prod ( [1:i] ) );
Пример для версий Wolfram Mathematica 7.0.1.0
В данном языке факториал определяется как и в обыкновенной алгебре: x! .
Print[Input["Input Number"]!];
Пример для версий Euphoria 3.1.1
Используется итеративное определение факториала
integer f
f = 1
for n = 0 to 15 do
printf(1,"%d! = %d\n",{n,f})
f *= n+1
end for