如何找到阶乘?

发布于 2024-08-24 13:22:13 字数 1436 浏览 6 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

书信已泛黄 2024-08-31 13:22:13

这适用于正整数的阶乘(尽管是一个非常小的子集):

unsigned long factorial(unsigned long f)
{
    if ( f == 0 ) 
        return 1;
    return(f * factorial(f - 1));
}

printf("%i", factorial(5));

由于您的问题的性质(以及您已经承认的水平),该解决方案更多地基于解决这个问题的概念,而不是基于一个函数将在下一个“排列引擎”中使用。

This will work for the factorial (although a very small subset) of positive integers:

unsigned long factorial(unsigned long f)
{
    if ( f == 0 ) 
        return 1;
    return(f * factorial(f - 1));
}

printf("%i", factorial(5));

Due to the nature of your problem (and level that you have admitted), this solution is based more in the concept of solving this rather than a function that will be used in the next "Permutation Engine".

翻了热茶 2024-08-31 13:22:13

这会计算直到 ULONG_MAX 的非负整数[*] 的阶乘,其中的位数太多,以至于您的机器不太可能存储更多的位数,即使它有时间计算它们。使用 GNU 多精度库,您需要链接该库。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>

void factorial(mpz_t result, unsigned long input) {
    mpz_set_ui(result, 1);
    while (input > 1) {
        mpz_mul_ui(result, result, input--);
    }
}

int main() {
    mpz_t fact;
    unsigned long input = 0;
    char *buf;

    mpz_init(fact);
    scanf("%lu", &input);
    factorial(fact, input);

    buf = malloc(mpz_sizeinbase(fact, 10) + 1);
    assert(buf);
    mpz_get_str(buf, 10, fact);
    printf("%s\n", buf);

    free(buf);
    mpz_clear(fact);
}

示例输出:

$ make factorial CFLAGS="-L/bin/ -lcyggmp-3 -pedantic" -B && ./factorial
cc -L/bin/ -lcyggmp-3 -pedantic    factorial.c   -o factorial
100
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

[*] 如果您用“数字”表示其他内容,那么您必须更具体。尽管 Pascal 做出了勇敢的努力,通过使用 Gamma 函数来扩展域,但我不知道定义了阶乘的任何其他数字。

This calculates factorials of non-negative integers[*] up to ULONG_MAX, which will have so many digits that it's unlikely your machine can store a whole lot more, even if it has time to calculate them. Uses the GNU multiple precision library, which you need to link against.

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>

void factorial(mpz_t result, unsigned long input) {
    mpz_set_ui(result, 1);
    while (input > 1) {
        mpz_mul_ui(result, result, input--);
    }
}

int main() {
    mpz_t fact;
    unsigned long input = 0;
    char *buf;

    mpz_init(fact);
    scanf("%lu", &input);
    factorial(fact, input);

    buf = malloc(mpz_sizeinbase(fact, 10) + 1);
    assert(buf);
    mpz_get_str(buf, 10, fact);
    printf("%s\n", buf);

    free(buf);
    mpz_clear(fact);
}

Example output:

$ make factorial CFLAGS="-L/bin/ -lcyggmp-3 -pedantic" -B && ./factorial
cc -L/bin/ -lcyggmp-3 -pedantic    factorial.c   -o factorial
100
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

[*] If you mean something else by "number" then you'll have to be more specific. I'm not aware of any other numbers for which the factorial is defined, despite valiant efforts by Pascal to extend the domain by use of the Gamma function.

绳情 2024-08-31 13:22:13

当你可以在 Haskell 中实现时,为什么要在 C 中实现呢

新生 Haskell 程序员

fac n = 如果 n == 0 
           那么 1
           否则 n * fac (n-1)

麻省理工学院二年级 Haskell 程序员(大一时学习了Scheme)

fac = (\(n) ->;
        (如果((==)n 0)
            那么 1
            否则 ((*) n (fac ((-) n 1)))))

初级 Haskell 程序员(Peano 初学者)

<前><代码>fac 0 = 1
fac (n+1) = (n+1) * fac n

另一位初级 Haskell 程序员(读到 n+k 模式是“a
Haskell 的恶心部分”1 并加入了“Ban n+k”
模式”-运动[2])

<前><代码>fac 0 = 1
面 n = n * 面 (n-1)

高级 Haskell 程序员(投票给尼克松·布坎南·布什 —
“向右倾斜”)

fac n =foldr (*) 1 [1..n]

另一位高级 Haskell 程序员(投票给 McGovern Biafra
纳德 —“向左倾斜”)

fac n = Foldl (*) 1 [1..n]

另一位高级 Haskell 程序员(他来时向右倾斜太远了)
再次向左返回!)

--使用foldr模拟foldl

fac n =foldr(\xgn -> g(x*n)) id [1..n] 1

记忆 Haskell 程序员(每天服用银杏叶)

facs = scanl (*) 1 [1..]

事实 n = 事实 !! n

毫无意义(咳咳)“无点”Haskell 程序员(就读于
牛津)

fac = 文件夹 (*) 1 。枚举FromTo 1

迭代 Haskell 程序员(前 Pascal 程序员)

fac n = 结果(用于初始化下一个完成)
        其中初始化 = (0,1)
              下一个 (i,m) = (i+1, m * (i+1))
              完成 (i,_) = i==n
              结果 (_,m) = m

对于 ind = 直到 dni

迭代单行 Haskell 程序员(前 APL 和 C 程序员)

fac n = snd (until ((>n) . fst) (\(i,m) -> (i+1, i*m)) (1,1))

积累Haskell程序员(建立一个快速的高潮)

facAcc a 0 = a
facAcc an = facAcc (n*a) (n-1)

fac = facAcc 1

继续通过 Haskell 程序员(早期提出了 RABBITS
年,然后搬到新泽西州)

facCps k 0 = k 1
facCps kn = facCps (k . (n *)) (n-1)

fac = facCps id

童子军 Haskell 程序员(喜欢打结;总是“虔诚”,
他属于最小定点教会 [8])

<前><代码>yf = f (yf)

fac = y (\fn -> if (n==0) then 1 else n * f (n-1))

组合 Haskell 程序员(避开变量,如果不是的话)
混淆;所有这些柯里化只是一个阶段,尽管很少
阻碍)

sfgx = fx (gx)

kxy=x

bfgx = f (gx)

cfgx=fxg

yf = f (yf)

cond pfgx = 如果 px 那么 fx 否则 gx

fac = y (b (cond ((==) 0) (k 1)) (b (s (*)) (cb pred)))

列表编码 Haskell 程序员(更喜欢以一元计数)

arb = () -- “undefined”也是一个很好的 RHS,“arb”也是如此 :)

Listenc n = 复制 n arb
listprj f = 长度。 f.听

列表产品 xs ys = [ i (x,y) | x<-xs, y<-ys]
                 其中 i _ = arb

facl[]=listenc 1
facl n@(_:pred) = listprod n (facl pred)

fac = 列表prj facl

解释型 Haskell 程序员(从未“遇到过一种语言”,他没有
喜欢)

——动态类型术语语言

数据项 = Occ Var
          |使用Prim
          |点亮整数
          |应用程序 术语 术语
          |绝对方差项
          |记录变量项

类型变量 = 字符串
类型 Prim = 字符串


-- 值域,包括函数

数据值 = Num 整数
           |布尔 布尔
           |乐趣(价值 -> 价值)

实例显示值,其中
  显示(数字 n)= 显示 n
  显示 (布尔 b) = 显示 b
  显示(有趣_)=“”

prjFun (Fun f) = f
prjFun _ = 错误“函数值错误”

prjNum (Num n) = n
prjNum _ = 错误“数值错误”

prjBool (布尔 b) = b
prjBool _ = 错误“错误的布尔值”

binOp inj f = Fun (\i -> (Fun (\j -> inj (f (prjNum i) (prjNum j)))))


-- 将变量映射到值的环境

类型 Env = [(Var, Value)]

getval x env = 案例查找 x env of
                  只是 v -> v
                  没什么->错误(“无值” ++ x)


-- 基于环境的评价函数

eval env (Occ x) = getval x env
eval env (使用 c) = getval c prims
eval env (Lit k) = Num k
eval env (App mn) = prjFun (eval env m) (eval env n)
eval env (Abs xm) = Fun (\v -> eval ((x,v) : env) m)
eval env (Rec xm) = f 其中 f = eval ((x,f) : env) m


-- 语言原语的(固定)“环境”

次数 = binOp 数 (*)
减号 = binOp 编号 (-)
等于 = binOp Bool (==)
cond = Fun (\b -> Fun (\x -> Fun (\y -> if (prjBool b) then x else y)))

prims = [ ("*", 次), ("-", 减号), ("==", 等于), ("if", cond) ]


-- 代表阶乘的术语和用于评估的“包装器”

facTerm = Rec“f”(Abs“n” 
              (应用程序(应用程序(使用“如果”)
                   (应用程序(应用程序(使用“==”)(Occ“n”))(点亮0)))(点亮1))
                   (应用程序(应用程序(使用“*”)(Occ“n”))
                        (应用程序(Occ“f”)  
                             (应用程序(应用程序(使用“-”)(Occ“n”))(Lit 1))))))

fac n = prjNum(eval[](App facTerm(Lit n)))

静态 Haskell 程序员(他用类来做,他有那个
资助琼斯!在 Thomas Hallgren 的“功能与乐趣”之后
依赖关系”[7])

--静态 Peano 构造函数和数字

数据归零
数据顺利

类型一 = Succ 零
类型二=成功一
类型三=成功二
类型四 = Succ 三


--静态皮亚诺斯的动态代表

零 = 未定义 :: 零
一 = 未定义 :: 一
二 = 未定义 :: 二
三 = 未定义 :: 三
四 = 未定义 :: 四


-- 补充,a la Prolog

类添加 abc | ab-> c 哪里
  添加::a-> b-> c
  
实例加零 bb
实例添加 abc =>添加 (Succ a) b (Succ c)


——Prolog 中的乘法

类 Mul abc | ab-> c 哪里
  mul :: a ->; b-> c

实例 Mul 零 b 零
实例(Mul abc,Add bcd)=> Mul (Succ a) bd


-- 阶乘,a la Prolog

Fac ab 类 |一个-> b 哪里
  fac::a->乙

实例 Fac 零一
实例(Fac nk, Mul(Succ n) km) => Fac (Succ n) m

-- 尝试“例如”(抱歉):
-- 
-- :t 事实四

刚毕业的 Haskell 程序员(研究生教育倾向于
将人们从诸如效率等琐碎的担忧中解放出来
基于硬件的整数)

-- 自然数,拉皮亚诺

数据 Nat = 0 |苏克纳特


-- 迭代和一些应用

iter zs 零 = z
iter zs (Succ n) = s (iter zsn)

加 n = iter n Succ
乘数 n = 迭代零(加上 n)


-- 原始递归

primrec zs 零 = z
primrec zs (Succ n) = sn (primrec zsn)


-- 阶乘的两个版本

面 = snd . iter (一,一) (\(a,b) -> (Succ a, mult ab))
fac' = primrec one (mult . Succ)


-- 为了方便和测试(尝试例如“fac 5”)

int = 迭代 0 (1+)

实例显示 Nat 在哪里
  显示 = 显示 .整数

(零:一:二:三:四:五:_) = 迭代 Succ 零

 
Origamist Haskell 程序员
(总是从“基本的鸟折叠”开始)

--(柯里化,列表)折叠和应用程序

折叠 cn[] = n
折叠 cn (x:xs) = cx (折叠 cn xs)

产品 = 折叠 (*) 1


--(柯里化、基于布尔、列表)展开和应用程序

展开 pfgx = 
  如果 px 则 [] 
     else fx : 展开 pfg (gx)

downfrom =展开(==0) id pred


-- hylomorphisms,原样或“展开”(哎呀!抱歉......)

重新折叠 cnpfg = 折叠 cn 。展开 pfg

重新折叠'cnpfgx = 
  如果 px 则 n 
     else c (fx) (重新折叠' cnpfg (gx))
                         

-- 阶乘的几个版本,全部(扩展上)等效

事实=产品。从下
fac' = 重新折叠 (*) 1 (==0) id pred
fac'' = 重新折叠' (*) 1 (==0) id pred

有笛卡尔倾向的 Haskell 程序员(更喜欢希腊食物,
避免辛辣的印度菜;灵感来自 Lex Augusteijn 的“排序”
态射”[3])

--(基于产品,列表)变形和应用

目录 (n,c) [] = n
cata (n,c) (x:xs) = c (x, cata (n,c) xs)

mult = 咖喱 (*)
产品 = cata (1, mult)


--(基于联产品,列表)变形和应用

ana f = 任一 (const []) (cons .pair (id, ana f)) 。 f

缺点 = 不咖喱 (:)

downfrom = ana 不可数

不可计数 0 = 左 ()
不可数 n = 右 (n, n-1)


-- 列表亲质性的两种变体

hylo fg = 目录 g 。安娜夫

hylo' f (n,c) = 任一 (const n) (c .pair (id, hylo' f (c,n))) 。 f

对 (f,g) (x,y) = (fx, gy)


-- 阶乘的几个版本,全部(扩展上)等效

事实=产品。从下
fac' = hylo uncount (1, mult)
fac'' = hylo' uncount (1, mult)

博士。 Haskell程序员(吃了太多香蕉眼睛都肿了
出去,现在他需要新镜头!)

--基于函子的显式类型递归

newtype Mu f = Mu (f (Mu f)) 推导 显示

在 x = Mu x
输出 (Mu x) = x


-- cata-和ana-morphisms,现在用于*任意*(常规)基函子

卡塔 phi = phi . fmap(卡塔菲)。出去
ana psi = 在 . fmap (ana psi) 。磅/平方英寸


-- 自然数的基本函子和数据类型,
-- 使用柯里化消除运算符

数据 N b = 0 | Succ b 推导显示

实例函子 N 其中
  fmap f = nelim 零 (Succ . f)

nelim zs 零 = z
nelim zs (Succ n) = sn

类型 Nat = Mu N


-- 转换为内部号码、便利性和应用程序

int = cata (nelim 0 (1+))

实例显示 Nat 在哪里
  显示 = 显示 .整数

零=零
吸=吸进去。 Succ——请原谅我的“法语”(前奏冲突)

加 n = cata (nelim n 吸 )
mult n = cata(nelim 零(加 n))


-- 列表的基本函子和数据类型

数据 L ab = Nil |缺点 ab 派生 显示

实例函子 (L a) 其中
  fmap f = lelim Nil (\ab -> Cons a (fb))

lelim nc 无 = n
lelim nc (Cons ab) = cab

类型列表 a = Mu (L a)


-- 转换为内部列表、便利性和应用程序

列表 = cata(lelim[](:))

实例显示=>显示(列表 a)其中
  显示 = 显示 .列表

prod = cata(lelim(吸零)mult)

upto = ana(nelim Nil(diag(Cons.suck)).out)

诊断 fx = fxx

事实=产品。高达

 
博士后 Haskell 程序员
(摘自 Uustalu、Vene 和 Pardo 的“Comonads 的递归方案”[4])

-- 带有函子和变形的显式类型递归

新类型 Mu f = In (f (Mu f))

unIn (In x) = x

卡塔 phi = phi . fmap(卡塔菲)。未输入


-- 自然数的基本函子和数据类型,
-- 使用本地定义的“消除器”

数据 Nc = Z | SC

实例函子 N 其中
  fmap g Z = Z
  fmap g (S x) = S (gx)

类型 Nat = Mu N

零 = 在 Z 中
吸 n = In (S n)

添加 m = cata phi 其中
  Φ Z = m
  phi (S f) = 吸 f

mult m = cata phi 其中
  phi Z = 零
  phi (S f) = 添加 mf


-- 显式乘积及其功能作用

数据产品 ec = 对 ce

outl(xy 对)= x
outr(xy 对)= y

叉 fgx = 对 (fx) (gx)

实例函子 (Prod e) 其中
  fmap g = fork (g . outl) outr


-- comonads,单子的绝对“对立面”

类函子 n => Comonad n 哪里
  外部:: na ->一个
  dupl::na-> n (na)

实例 Comonad (Prod e) 其中
  外部 = 输出
  dupl = 分叉 ID 外部


-- 广义变态、对称和拟态

gcata :: (函子 f, Comonad n) =>
           (对于所有 a.f (na) -> n (fa))
             -> (f(nc)→c)→ Mu f-> c

gcata 距离 phi = extr 。 cata(fmap phi .dist .fmap dupl)

zygo chi = gcata (fork (fmap outl) (chi . fmap outr))

para :: 函子 f => (f(Prod(Mu f)c)→c)→ Mu f-> c
para = zygo In


-- 阶乘,*困难*的方式!

fac = para phi 其中
  phi Z = 吸零
  phi (S (Pair fn)) = mult f (吸 n)
  

-- 为了方便和测试

int = cata phi 其中
  ΦZ = 0
  phi (S f) = 1 + f

实例显示 (Mu N) 其中
  显示 = 显示 .整数

终身教授(向新生教授 Haskell)

fac n = 产品 [1..n]
  • 内容来自威拉米特大学 Fritz Ruehr 的 Haskell 程序员的进化 - 201 年 7 月 11 日

Why do it in C when you can do it in Haskell:

Freshman Haskell programmer

fac n = if n == 0 
           then 1
           else n * fac (n-1)

Sophomore Haskell programmer, at MIT (studied Scheme as a freshman)

fac = (\(n) ->
        (if ((==) n 0)
            then 1
            else ((*) n (fac ((-) n 1)))))

Junior Haskell programmer (beginning Peano player)

fac  0    =  1
fac (n+1) = (n+1) * fac n

Another junior Haskell programmer (read that n+k patterns are “a
disgusting part of Haskell” 1 and joined the “Ban n+k
patterns”-movement [2])

fac 0 = 1
fac n = n * fac (n-1)

Senior Haskell programmer (voted for Nixon Buchanan Bush —
“leans right”)

fac n = foldr (*) 1 [1..n]

Another senior Haskell programmer (voted for McGovern Biafra
Nader — “leans left”)

fac n = foldl (*) 1 [1..n]

Yet another senior Haskell programmer (leaned so far right he came
back left again!)

-- using foldr to simulate foldl

fac n = foldr (\x g n -> g (x*n)) id [1..n] 1

Memoizing Haskell programmer (takes Ginkgo Biloba daily)

facs = scanl (*) 1 [1..]

fac n = facs !! n

Pointless (ahem) “Points-free” Haskell programmer (studied at
Oxford)

fac = foldr (*) 1 . enumFromTo 1

Iterative Haskell programmer (former Pascal programmer)

fac n = result (for init next done)
        where init = (0,1)
              next   (i,m) = (i+1, m * (i+1))
              done   (i,_) = i==n
              result (_,m) = m

for i n d = until d n i

Iterative one-liner Haskell programmer (former APL and C programmer)

fac n = snd (until ((>n) . fst) (\(i,m) -> (i+1, i*m)) (1,1))

Accumulating Haskell programmer (building up to a quick climax)

facAcc a 0 = a
facAcc a n = facAcc (n*a) (n-1)

fac = facAcc 1

Continuation-passing Haskell programmer (raised RABBITS in early
years, then moved to New Jersey)

facCps k 0 = k 1
facCps k n = facCps (k . (n *)) (n-1)

fac = facCps id

Boy Scout Haskell programmer (likes tying knots; always “reverent,”
he belongs to the Church of the Least Fixed-Point [8])

y f = f (y f)

fac = y (\f n -> if (n==0) then 1 else n * f (n-1))

Combinatory Haskell programmer (eschews variables, if not
obfuscation; all this currying’s just a phase, though it seldom
hinders)

s f g x = f x (g x)

k x y   = x

b f g x = f (g x)

c f g x = f x g

y f     = f (y f)

cond p f g x = if p x then f x else g x

fac  = y (b (cond ((==) 0) (k 1)) (b (s (*)) (c b pred)))

List-encoding Haskell programmer (prefers to count in unary)

arb = ()    -- "undefined" is also a good RHS, as is "arb" :)

listenc n = replicate n arb
listprj f = length . f . listenc

listprod xs ys = [ i (x,y) | x<-xs, y<-ys ]
                 where i _ = arb

facl []         = listenc  1
facl n@(_:pred) = listprod n (facl pred)

fac = listprj facl

Interpretive Haskell programmer (never “met a language” he didn't
like)

-- a dynamically-typed term language

data Term = Occ Var
          | Use Prim
          | Lit Integer
          | App Term Term
          | Abs Var  Term
          | Rec Var  Term

type Var  = String
type Prim = String


-- a domain of values, including functions

data Value = Num  Integer
           | Bool Bool
           | Fun (Value -> Value)

instance Show Value where
  show (Num  n) = show n
  show (Bool b) = show b
  show (Fun  _) = ""

prjFun (Fun f) = f
prjFun  _      = error "bad function value"

prjNum (Num n) = n
prjNum  _      = error "bad numeric value"

prjBool (Bool b) = b
prjBool  _       = error "bad boolean value"

binOp inj f = Fun (\i -> (Fun (\j -> inj (f (prjNum i) (prjNum j)))))


-- environments mapping variables to values

type Env = [(Var, Value)]

getval x env =  case lookup x env of
                  Just v  -> v
                  Nothing -> error ("no value for " ++ x)


-- an environment-based evaluation function

eval env (Occ x) = getval x env
eval env (Use c) = getval c prims
eval env (Lit k) = Num k
eval env (App m n) = prjFun (eval env m) (eval env n)
eval env (Abs x m) = Fun  (\v -> eval ((x,v) : env) m)
eval env (Rec x m) = f where f = eval ((x,f) : env) m


-- a (fixed) "environment" of language primitives

times = binOp Num  (*)
minus = binOp Num  (-)
equal = binOp Bool (==)
cond  = Fun (\b -> Fun (\x -> Fun (\y -> if (prjBool b) then x else y)))

prims = [ ("*", times), ("-", minus), ("==", equal), ("if", cond) ]


-- a term representing factorial and a "wrapper" for evaluation

facTerm = Rec "f" (Abs "n" 
              (App (App (App (Use "if")
                   (App (App (Use "==") (Occ "n")) (Lit 0))) (Lit 1))
                   (App (App (Use "*")  (Occ "n"))
                        (App (Occ "f")  
                             (App (App (Use "-") (Occ "n")) (Lit 1))))))

fac n = prjNum (eval [] (App facTerm (Lit n)))

Static Haskell programmer (he does it with class, he’s got that
fundep Jones! After Thomas Hallgren’s “Fun with Functional
Dependencies” [7])

-- static Peano constructors and numerals

data Zero
data Succ n

type One   = Succ Zero
type Two   = Succ One
type Three = Succ Two
type Four  = Succ Three


-- dynamic representatives for static Peanos

zero  = undefined :: Zero
one   = undefined :: One
two   = undefined :: Two
three = undefined :: Three
four  = undefined :: Four


-- addition, a la Prolog

class Add a b c | a b -> c where
  add :: a -> b -> c
  
instance              Add  Zero    b  b
instance Add a b c => Add (Succ a) b (Succ c)


-- multiplication, a la Prolog

class Mul a b c | a b -> c where
  mul :: a -> b -> c

instance                           Mul  Zero    b Zero
instance (Mul a b c, Add b c d) => Mul (Succ a) b d


-- factorial, a la Prolog

class Fac a b | a -> b where
  fac :: a -> b

instance                                Fac  Zero    One
instance (Fac n k, Mul (Succ n) k m) => Fac (Succ n) m

-- try, for "instance" (sorry):
-- 
--     :t fac four

Beginning graduate Haskell programmer (graduate education tends to
liberate one from petty concerns about, e.g., the efficiency of
hardware-based integers)

-- the natural numbers, a la Peano

data Nat = Zero | Succ Nat


-- iteration and some applications

iter z s  Zero    = z
iter z s (Succ n) = s (iter z s n)

plus n = iter n     Succ
mult n = iter Zero (plus n)


-- primitive recursion

primrec z s  Zero    = z
primrec z s (Succ n) = s n (primrec z s n)


-- two versions of factorial

fac  = snd . iter (one, one) (\(a,b) -> (Succ a, mult a b))
fac' = primrec one (mult . Succ)


-- for convenience and testing (try e.g. "fac five")

int = iter 0 (1+)

instance Show Nat where
  show = show . int

(zero : one : two : three : four : five : _) = iterate Succ Zero

 
Origamist Haskell programmer
(always starts out with the “basic Bird fold”)

-- (curried, list) fold and an application

fold c n []     = n
fold c n (x:xs) = c x (fold c n xs)

prod = fold (*) 1


-- (curried, boolean-based, list) unfold and an application

unfold p f g x = 
  if p x 
     then [] 
     else f x : unfold p f g (g x)

downfrom = unfold (==0) id pred


-- hylomorphisms, as-is or "unfolded" (ouch! sorry ...)

refold  c n p f g   = fold c n . unfold p f g

refold' c n p f g x = 
  if p x 
     then n 
     else c (f x) (refold' c n p f g (g x))
                         

-- several versions of factorial, all (extensionally) equivalent

fac   = prod . downfrom
fac'  = refold  (*) 1 (==0) id pred
fac'' = refold' (*) 1 (==0) id pred

Cartesianally-inclined Haskell programmer (prefers Greek food,
avoids the spicy Indian stuff; inspired by Lex Augusteijn’s “Sorting
Morphisms” [3])

-- (product-based, list) catamorphisms and an application

cata (n,c) []     = n
cata (n,c) (x:xs) = c (x, cata (n,c) xs)

mult = uncurry (*)
prod = cata (1, mult)


-- (co-product-based, list) anamorphisms and an application

ana f = either (const []) (cons . pair (id, ana f)) . f

cons = uncurry (:)

downfrom = ana uncount

uncount 0 = Left  ()
uncount n = Right (n, n-1)


-- two variations on list hylomorphisms

hylo  f  g    = cata g . ana f

hylo' f (n,c) = either (const n) (c . pair (id, hylo' f (c,n))) . f

pair (f,g) (x,y) = (f x, g y)


-- several versions of factorial, all (extensionally) equivalent

fac   = prod . downfrom
fac'  = hylo  uncount (1, mult)
fac'' = hylo' uncount (1, mult)

Ph.D. Haskell programmer (ate so many bananas that his eyes bugged
out, now he needs new lenses!)

-- explicit type recursion based on functors

newtype Mu f = Mu (f (Mu f))  deriving Show

in      x  = Mu x
out (Mu x) = x


-- cata- and ana-morphisms, now for *arbitrary* (regular) base functors

cata phi = phi . fmap (cata phi) . out
ana  psi = in  . fmap (ana  psi) . psi


-- base functor and data type for natural numbers,
-- using a curried elimination operator

data N b = Zero | Succ b  deriving Show

instance Functor N where
  fmap f = nelim Zero (Succ . f)

nelim z s  Zero    = z
nelim z s (Succ n) = s n

type Nat = Mu N


-- conversion to internal numbers, conveniences and applications

int = cata (nelim 0 (1+))

instance Show Nat where
  show = show . int

zero = in   Zero
suck = in . Succ       -- pardon my "French" (Prelude conflict)

plus n = cata (nelim n     suck   )
mult n = cata (nelim zero (plus n))


-- base functor and data type for lists

data L a b = Nil | Cons a b  deriving Show

instance Functor (L a) where
  fmap f = lelim Nil (\a b -> Cons a (f b))

lelim n c  Nil       = n
lelim n c (Cons a b) = c a b

type List a = Mu (L a)


-- conversion to internal lists, conveniences and applications

list = cata (lelim [] (:))

instance Show a => Show (List a) where
  show = show . list

prod = cata (lelim (suck zero) mult)

upto = ana (nelim Nil (diag (Cons . suck)) . out)

diag f x = f x x

fac = prod . upto

 
Post-doc Haskell programmer
(from Uustalu, Vene and Pardo’s “Recursion Schemes from Comonads” [4])

-- explicit type recursion with functors and catamorphisms

newtype Mu f = In (f (Mu f))

unIn (In x) = x

cata phi = phi . fmap (cata phi) . unIn


-- base functor and data type for natural numbers,
-- using locally-defined "eliminators"

data N c = Z | S c

instance Functor N where
  fmap g  Z    = Z
  fmap g (S x) = S (g x)

type Nat = Mu N

zero   = In  Z
suck n = In (S n)

add m = cata phi where
  phi  Z    = m
  phi (S f) = suck f

mult m = cata phi where
  phi  Z    = zero
  phi (S f) = add m f


-- explicit products and their functorial action

data Prod e c = Pair c e

outl (Pair x y) = x
outr (Pair x y) = y

fork f g x = Pair (f x) (g x)

instance Functor (Prod e) where
  fmap g = fork (g . outl) outr


-- comonads, the categorical "opposite" of monads

class Functor n => Comonad n where
  extr :: n a -> a
  dupl :: n a -> n (n a)

instance Comonad (Prod e) where
  extr = outl
  dupl = fork id outr


-- generalized catamorphisms, zygomorphisms and paramorphisms

gcata :: (Functor f, Comonad n) =>
           (forall a. f (n a) -> n (f a))
             -> (f (n c) -> c) -> Mu f -> c

gcata dist phi = extr . cata (fmap phi . dist . fmap dupl)

zygo chi = gcata (fork (fmap outl) (chi . fmap outr))

para :: Functor f => (f (Prod (Mu f) c) -> c) -> Mu f -> c
para = zygo In


-- factorial, the *hard* way!

fac = para phi where
  phi  Z             = suck zero
  phi (S (Pair f n)) = mult f (suck n)
  

-- for convenience and testing

int = cata phi where
  phi  Z    = 0
  phi (S f) = 1 + f

instance Show (Mu N) where
  show = show . int

Tenured professor (teaching Haskell to freshmen)

fac n = product [1..n]
  • Content from The Evolution of a Haskell Programmer by Fritz Ruehr, Willamette University - 11 July 01
三五鸿雁 2024-08-31 13:22:13

感谢 Christoph,一个适用于相当多“数字”的 C99 解决方案:

#include <math.h>
#include <stdio.h>

double fact(double x)
{
  return tgamma(x+1.);
}

int main()
{
  printf("%f %f\n", fact(3.0), fact(5.0));
  return 0;
}

产生 6.000000 120.000000

Thanks to Christoph, a C99 solution that works for quite a few "numbers":

#include <math.h>
#include <stdio.h>

double fact(double x)
{
  return tgamma(x+1.);
}

int main()
{
  printf("%f %f\n", fact(3.0), fact(5.0));
  return 0;
}

produces 6.000000 120.000000

我要还你自由 2024-08-31 13:22:13

对于大 n,您可能会遇到一些问题,您可能需要使用斯特林近似:

即:

alt text

For large n you may run into some issues and you may want to use Stirling's approximation:

Which is:

alt text

山有枢 2024-08-31 13:22:13

如果您的主要目标是一个看起来有趣的函数:(

int facorial(int a) {
   int b = 1, c, d, e;
   a--;
   for (c = a; c > 0; c--)
   for (d = b; d > 0; d--)
   for (e = c; e > 0; e--)
   b++;
   return b;
}

不推荐作为实际使用的算法。)

If your main objective is an interesting looking function:

int facorial(int a) {
   int b = 1, c, d, e;
   a--;
   for (c = a; c > 0; c--)
   for (d = b; d > 0; d--)
   for (e = c; e > 0; e--)
   b++;
   return b;
}

(Not recommended as an algorithm for real use.)

猫九 2024-08-31 13:22:13

尾递归版本:

long factorial(long n)
{
    return tr_fact(n, 1);
}
static long tr_fact(long n, long result)
{
    if(n==1)
        return result;
    else
        return tr_fact(n-1, n*result);
}

a tail-recursive version:

long factorial(long n)
{
    return tr_fact(n, 1);
}
static long tr_fact(long n, long result)
{
    if(n==1)
        return result;
    else
        return tr_fact(n-1, n*result);
}
茶色山野 2024-08-31 13:22:13

在 C99(或 Java)中,我会像这样迭代地编写阶乘函数:

int factorial(int n)
{
    int result = 1;
    for (int i = 2; i <= n; i++)
    {
        result *= i;
    }
    return result;
}
  • C 不是函数式语言,您不能依赖尾部调用优化。因此,除非需要,否则不要在 C(或 Java)中使用递归。

  • 仅仅因为阶乘经常被用作递归的第一个示例,并不意味着您需要递归来计算它。

    仅仅

  • 如果 n 太大,这将静静地溢出,这是 C(和 Java)中的惯例。

    如果

  • 如果 int 可以表示的数字对于您要计算的阶乘来说太小,则选择其他数字类型。如果需要更大一点,则为 long long;如果 n 不太大并且您不介意一些不精确,则为 float 或 double;如果您想要真正大阶乘的精确值,则为大整数。

In C99 (or Java) I would write the factorial function iteratively like this:

int factorial(int n)
{
    int result = 1;
    for (int i = 2; i <= n; i++)
    {
        result *= i;
    }
    return result;
}
  • C is not a functional language and you can't rely on tail-call optimization. So don't use recursion in C (or Java) unless you need to.

  • Just because factorial is often used as the first example for recursion it doesn't mean you need recursion to compute it.

  • This will overflow silently if n is too big, as is the custom in C (and Java).

  • If the numbers int can represent are too small for the factorials you want to compute then choose another number type. long long if it needs be just a little bit bigger, float or double if n isn't too big and you don't mind some imprecision, or big integers if you want the exact values of really big factorials.

清旖 2024-08-31 13:22:13

这是一个使用 OPENSSL 的 BIGNUM 实现的 C 程序,因此对学生来说不是特别有用。 (当然,接受 BIGNUM 作为输入参数是疯狂的,但有助于演示 BIGNUM 之间的交互)。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <openssl/crypto.h>
#include <openssl/bn.h>

BIGNUM *factorial(const BIGNUM *num)
{
    BIGNUM *count = BN_new();
    BIGNUM *fact = NULL;
    BN_CTX *ctx = NULL;

    BN_one(count);
    if( BN_cmp(num, BN_value_one()) <= 0 )
    {
        return count;
    }

    ctx = BN_CTX_new();
    fact = BN_dup(num);
    BN_sub(count, fact, BN_value_one());
    while( BN_cmp(count, BN_value_one()) > 0 )
    {
        BN_mul(fact, count, fact, ctx);
        BN_sub(count, count, BN_value_one());
    }

    BN_CTX_free(ctx);
    BN_free(count);

    return fact;
}

此测试程序展示了如何创建输入数字以及如何处理返回值:

int main(int argc, char *argv[])
{
    const char *test_cases[] =
    {
        "0", "1",
        "1", "1",
        "4", "24",
        "15", "1307674368000",
        "30", "265252859812191058636308480000000",
        "56", "710998587804863451854045647463724949736497978881168458687447040000000000000",
        NULL, NULL
    };
    int index = 0;
    BIGNUM *bn = NULL;
    BIGNUM *fact = NULL;
    char *result_str = NULL;

    for( index = 0; test_cases[index] != NULL; index += 2 )
    {
        BN_dec2bn(&bn, test_cases[index]);

        fact = factorial(bn);

        result_str = BN_bn2dec(fact);
        printf("%3s: %s\n", test_cases[index], result_str);
        assert(strcmp(result_str, test_cases[index + 1]) == 0);

        OPENSSL_free(result_str);
        BN_free(fact);
        BN_free(bn);
        bn = NULL;
    }

    return 0;
}

使用 gcc 编译:

gcc factorial.c -o factorial -g -lcrypto

Here's a C program that uses OPENSSL's BIGNUM implementation, and therefore is not particularly useful for students. (Of course accepting a BIGNUM as the input parameter is crazy, but helpful for demonstrating interaction between BIGNUMs).

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <openssl/crypto.h>
#include <openssl/bn.h>

BIGNUM *factorial(const BIGNUM *num)
{
    BIGNUM *count = BN_new();
    BIGNUM *fact = NULL;
    BN_CTX *ctx = NULL;

    BN_one(count);
    if( BN_cmp(num, BN_value_one()) <= 0 )
    {
        return count;
    }

    ctx = BN_CTX_new();
    fact = BN_dup(num);
    BN_sub(count, fact, BN_value_one());
    while( BN_cmp(count, BN_value_one()) > 0 )
    {
        BN_mul(fact, count, fact, ctx);
        BN_sub(count, count, BN_value_one());
    }

    BN_CTX_free(ctx);
    BN_free(count);

    return fact;
}

This test program shows how to create a number for input and what to do with the return value:

int main(int argc, char *argv[])
{
    const char *test_cases[] =
    {
        "0", "1",
        "1", "1",
        "4", "24",
        "15", "1307674368000",
        "30", "265252859812191058636308480000000",
        "56", "710998587804863451854045647463724949736497978881168458687447040000000000000",
        NULL, NULL
    };
    int index = 0;
    BIGNUM *bn = NULL;
    BIGNUM *fact = NULL;
    char *result_str = NULL;

    for( index = 0; test_cases[index] != NULL; index += 2 )
    {
        BN_dec2bn(&bn, test_cases[index]);

        fact = factorial(bn);

        result_str = BN_bn2dec(fact);
        printf("%3s: %s\n", test_cases[index], result_str);
        assert(strcmp(result_str, test_cases[index + 1]) == 0);

        OPENSSL_free(result_str);
        BN_free(fact);
        BN_free(bn);
        bn = NULL;
    }

    return 0;
}

Compiled with gcc:

gcc factorial.c -o factorial -g -lcrypto
场罚期间 2024-08-31 13:22:13
int factorial(int n){
    return n <= 1 ? 1 : n * factorial(n-1);
}
int factorial(int n){
    return n <= 1 ? 1 : n * factorial(n-1);
}
逐鹿 2024-08-31 13:22:13

您可以使用以下代码来完成此操作。

#include    <stdio.h>
#include    <stdlib.h>

int main()
{
   int x, number, fac;
   fac = 1;
   printf("Enter a number:\n");
   scanf("%d",&number);

   if(number<0)
   {
      printf("Factorial not defined for negative numbers.\n");
      exit(0);
   }

   for(x = 1; x <= number; x++)
   {
      if (number >= 0)
         fac = fac * x;
      else
         fac=1;
   }

   printf("%d! = %d\n", number, fac);
} 

You use the following code to do it.

#include    <stdio.h>
#include    <stdlib.h>

int main()
{
   int x, number, fac;
   fac = 1;
   printf("Enter a number:\n");
   scanf("%d",&number);

   if(number<0)
   {
      printf("Factorial not defined for negative numbers.\n");
      exit(0);
   }

   for(x = 1; x <= number; x++)
   {
      if (number >= 0)
         fac = fac * x;
      else
         fac=1;
   }

   printf("%d! = %d\n", number, fac);
} 
吐个泡泡 2024-08-31 13:22:13

对于大数,您可能可以得到一个近似解,tgamma 可以从 math.h 中为您提供 (n!= Gamma(n+1))。如果您想要更大的数字,它们将无法容纳在双精度数中,因此您应该使用 lgamma(gamma 函数的自然对数)。

如果您在没有完整 C99 math.h 的地方工作,您可以自己轻松地执行此类操作:

double logfactorial(int n) {
  double fac = 0.0;
  for ( ; n>1 ; n--) fac += log(fac);
  return fac;
}

For large numbers you probably can get away with an approximate solution, which tgamma gives you (n! = Gamma(n+1)) from math.h. If you want even larger numbers, they won't fit in a double, so you should use lgamma (natural log of the gamma function) instead.

If you're working somewhere without a full C99 math.h, you can easily do this type of thing yourself:

double logfactorial(int n) {
  double fac = 0.0;
  for ( ; n>1 ; n--) fac += log(fac);
  return fac;
}
暮光沉寂 2024-08-31 13:22:13

我认为在大多数情况下我不会使用它,但一种正在变得越来越不广泛使用的众所周知的做法是使用查找表。如果我们只使用内置类型,那么内存占用很小。

这只是另一种方法,让发布者意识到不同的技术。许多递归解决方案也可以被记忆,从而在算法运行时填充查找表,从而大大降低未来调用的成本(我猜有点像 .NET JIT 编译背后的原理)。

I don't think I'd use this in most cases, but one well-known practice which is becoming less widely used is to have a look-up table. If we're only working with built-in types, the memory hit is tiny.

Just another approach, to make the poster aware of a different technique. Many recursive solutions also can be memoized whereby a lookup table is filled in when the algorithm runs, drastically reducing the cost on future calls (kind of like the principle behind .NET JIT compilation I guess).

绮筵 2024-08-31 13:22:13

我们必须从 1 开始到指定的限制,例如 n。从 1*2*3...*n 开始。

在c中,我把它写成一个函数。

main()
{
 int n;
 scanf("%d",&n);
 printf("%ld",fact(n));
}

long int fact(int n)
{
 long int facto=1;
 int i; 
for(i=1;i<=n;i++)
 {
  facto=facto*i;
 }
 return facto;
}

We have to start from 1 to the limit specfied say n.Start from 1*2*3...*n.

In c, i am writing it as a function.

main()
{
 int n;
 scanf("%d",&n);
 printf("%ld",fact(n));
}

long int fact(int n)
{
 long int facto=1;
 int i; 
for(i=1;i<=n;i++)
 {
  facto=facto*i;
 }
 return facto;
}
你在我安 2024-08-31 13:22:13

简单的解决方案:

unsigned int factorial(unsigned int n)
{
   return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}

Simple solution:

unsigned int factorial(unsigned int n)
{
   return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}
骑趴 2024-08-31 13:22:13

最简单、最有效的是对数求和。如果您使用Log10,您将获得幂和指数。

伪代码

r=0
for i from 1 to n
    r= r + log(i)/log(10)

print "result is:", 10^(r-floor(r)) ,"*10^" , floor(r)

您可能需要添加代码,以便整数部分不会增加太多,从而降低准确性,但即使对于非常大的阶乘,结果也应该没问题。

Simplest and most efficient is to sum up logarithms. If you use Log10 you get power and exponent.

Pseudocode

r=0
for i from 1 to n
    r= r + log(i)/log(10)

print "result is:", 10^(r-floor(r)) ,"*10^" , floor(r)

You might need to add the code so the integer part does not increase too much and thus decrease accuracy, but result should be ok for even very large factorials.

坏尐絯 2024-08-31 13:22:13

C 中使用递归的示例

unsigned long factorial(unsigned long f)
{
        if (f) return(f * factorial(f - 1));
        return 1;
}

printf("%lu", factorial(5));

Example in C using recursion

unsigned long factorial(unsigned long f)
{
        if (f) return(f * factorial(f - 1));
        return 1;
}

printf("%lu", factorial(5));
安静 2024-08-31 13:22:13

我使用以下代码进行阶乘:

#include<stdio.h>
int main(){
  int i=1,f=1,n;

  printf("\n\nEnter a number: ");
  scanf("%d",&n);
  while(i<=n){
      f=f*i;
      i++;
  }
  printf("Factorial of is: %d",f);
  getch();
}

I used this code for Factorial:

#include<stdio.h>
int main(){
  int i=1,f=1,n;

  printf("\n\nEnter a number: ");
  scanf("%d",&n);
  while(i<=n){
      f=f*i;
      i++;
  }
  printf("Factorial of is: %d",f);
  getch();
}
又怨 2024-08-31 13:22:13

我会按照 先生的建议使用预先计算的查找表来完成此操作。男孩。这比迭代或递归解决方案计算得更快。它依赖于 n! 增长的速度,因为您可以在不溢出 unsigned long long 的情况下计算出最大的 n!(最大值为 18,446,744,073,709,551,615)只有 20!,因此您只需要一个包含 21 个元素的数组。下面是它在 c 中的样子:

long long factorial (int n) {
    long long f[22] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000};
    return f[n]; 
}

亲自看看!

I would do this with a pre-calculated lookup table as suggested by Mr. Boy. This would be faster to calculate than an iterative or recursive solution. It relies on how fast n! grows, because the largest n! you can calculate without overflowing an unsigned long long (max value of 18,446,744,073,709,551,615) is only 20!, so you only need an array with 21 elements. Here's how it would look in c:

long long factorial (int n) {
    long long f[22] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000};
    return f[n]; 
}

See for yourself!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文