Answers:
这是一个非常简单的数值计算问题,我们可以用斯特林近似法解决:
如您所见,该公式具有平方根,我们还将需要一种近似的方法。为此,我们将选择所谓的“巴比伦方法”,因为它可以说是最简单的方法:
请注意,以这种方式计算平方根是递归的一个很好的例子。
将所有内容放到Python程序中,可以为您解决以下问题:
def sqrt(x, n): # not the same n as below
return .5 * (sqrt(x, n - 1) + x / sqrt(x, n - 1)) if n > 0 else x
n = float(raw_input())
print (n / 2.718) ** n * sqrt(2 * 3.141 * n, 10)
通过简单的修改,上述程序可以输出整洁的阶乘表:
1! = 0.92215
2! = 1.91922
3! = 5.83747
4! = 23.51371
5! = 118.06923
6! = 710.45304
7! = 4983.54173
8! = 39931.74015
9! = 359838.58817
对于大多数应用程序,此方法应足够准确。
爪哇
public int factorial ( int n ) {
switch(n){
case 0: return 1;
case 1: return 1;
case 2: return 2;
case 3: return 6;
case 4: return 24;
case 5: return 120;
case 6: return 720;
case 7: return 5040;
case 8: return 40320;
case 9: return 362880;
case 10: return 3628800;
case 11: return 39916800;
case 12: return 479001600;
default : throw new IllegalArgumentException();
}
}
当然,解决任何问题的最佳方法是使用正则表达式:
import re
# adapted from http://stackoverflow.com/q/15175142/1333025
def multiple_replace(dict, text):
# Create a regular expression from the dictionary keys
regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
# Repeat while any replacements are made.
count = -1
while count != 0:
# For each match, look-up corresponding value in dictionary.
(text, count) = regex.subn(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
return text
fdict = {
'A': '@',
'B': 'AA',
'C': 'BBB',
'D': 'CCCC',
'E': 'DDDDD',
'F': 'EEEEEE',
'G': 'FFFFFFF',
'H': 'GGGGGGGG',
'I': 'HHHHHHHHH',
'J': 'IIIIIIIIII',
'K': 'JJJJJJJJJJJ',
'L': 'KKKKKKKKKKKK',
'M': 'LLLLLLLLLLLLL',
'N': 'MMMMMMMMMMMMMM',
'O': 'NNNNNNNNNNNNNNN',
'P': 'OOOOOOOOOOOOOOOO',
'Q': 'PPPPPPPPPPPPPPPPP',
'R': 'QQQQQQQQQQQQQQQQQQ',
'S': 'RRRRRRRRRRRRRRRRRRR',
'T': 'SSSSSSSSSSSSSSSSSSSS',
'U': 'TTTTTTTTTTTTTTTTTTTTT',
'V': 'UUUUUUUUUUUUUUUUUUUUUU',
'W': 'VVVVVVVVVVVVVVVVVVVVVVV',
'X': 'WWWWWWWWWWWWWWWWWWWWWWWW',
'Y': 'XXXXXXXXXXXXXXXXXXXXXXXXX',
'Z': 'YYYYYYYYYYYYYYYYYYYYYYYYYY'}
def fact(n):
return len(multiple_replace(fdict, chr(64 + n)))
if __name__ == "__main__":
print fact(7)
哈斯克尔
短代码是有效的代码,因此请尝试此操作。
fac = length . permutations . flip take [1..]
为什么拖钓:
我会笑任何写这篇文章的编码员。低效率是美丽的。对于实际上无法编写阶乘函数的任何Haskell程序员来说,也可能难以理解。
编辑:我前不久发布了这篇文章,但我想为以后的人和看不懂Haskell的人澄清一下。
此处的代码获取数字1到n的列表,创建该列表的所有排列的列表,并返回该列表的长度。在我的机器上,大约需要20分钟才能完成13 !!然后应该花四个小时才能完成14个工作!然后两个半天共15天!除了那里的某个时刻,您的内存不足。
编辑2:实际上,由于这是Haskell,您可能不会用完内存(请参阅下面的注释)。您也许可以强迫它评估列表并将其以某种方式保存在内存中,但是我对优化(和取消优化)Haskell的了解不足,无法确切地知道如何执行此操作。
[1..n]
。-的一个特定置换[1..n]
,其余置换归于thunk(中的多项式n
)。-该length
功能的累加器。
由于这是一个数学问题,因此使用专门设计用于解决数学问题的应用程序进行此计算是有意义的...
安装MATLAB。我认为,可以进行试用,但是这个非常复杂的问题可能很重要,值得购买完整版的应用程序。
在您的应用程序中包括MATLAB COM组件。
public string Factorial(uint n) {
MLApp.MLApp matlab = new MLApp.MLApp();
return matlab.Execute(String.Format("factorial({0})", n);
}
阶乘是较高级别的数学运算,一口气很难消化。解决此类问题的最佳解决方案是将一个大型任务分解为多个较小的任务。
现在,n!定义为1 * 2 * ... * n,因此,本质上是重复乘法,乘法只不过是重复加法。因此,考虑到这一点,以下解决了这个问题:
long Factorial(int n)
{
if(n==0)
{
return 1;
}
Stack<long> s = new Stack<long>();
for(var i=1;i<=n;i++)
{
s.Push(i);
}
var items = new List<long>();
var n2 = s.Pop();
while(s.Count >0)
{
var n3 = s.Pop();
items.AddRange(FactorialPart(n2,n3));
n2 = items.Sum();
}
return items.Sum()/(n-1);
}
IEnumerable<long> FactorialPart(long n1, long n2)
{
for(var i=0;i<n2;i++){
yield return n1;
}
}
#include <math.h>
int factorial(int n)
{
const double g = 7;
static const double p[] = { 0.99999999999980993, 676.5203681218851,
-1259.1392167224028, 771.32342877765313,
-176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6,
1.5056327351493116e-7 };
double z = n - 1 + 1;
double x = p[0];
int i;
for ( i = 1; i < sizeof(p)/sizeof(p[0]); ++i )
x += p[i] / (z + i);
return sqrt(2 * M_PI) * pow(z + g + 0.5, z + 0.5) * exp(-z -g -0.5) * x + 0.5;
}
巨魔:
z = n - 1 + 1
如果您知道发生了什么,最明显的“次优”代码()实际上是自记录的。p[]
使用序列系数的递归计算来进行计算!(这是伽玛函数的Lanczos近似值)
- 1 + 1
这里有什么要点吗?我的编译器对其进行了优化(这不是浮点数,在这种情况下优化代码可能会很危险),因此似乎不需要它。
double z = n - 1
是伽马函数近似值的一部分。的+ 1
距离关系,即gamma(n + 1) = n!
对于整数n。
我们都从大学知道,计算乘法的最有效方法是使用对数。毕竟,人们为什么还要使用对数表数百年?
因此,根据身份,a*b=e^(log(a)+log(b))
我们形成以下Python代码:
from math import log,exp
def fac_you(x):
return round(exp(sum(map(log,range(1,x+1)))))
for i in range(1,99):
print i,":",fac_you(i)
它会创建一个从1
到的数字列表x
,(+1
是必需的,因为Python很烂),计算每个的对数,将这些数字求和,将e增大为和的幂,最后将值四舍五入到最接近的整数(因为Python很烂) 。Python具有一个用于计算阶乘的内置函数,但是它仅适用于整数,因此它不能产生大数(因为Python很烂)。这就是为什么需要以上功能的原因。
顺便说一句,给学生的一个一般提示是,如果某些事情没有按预期运行,那可能是因为该语言很烂。
不幸的是,Javascript缺乏计算阶乘的内置方法。但是,您仍然可以在组合语言中使用其含义来确定该值:
数字n的阶乘是该大小的列表的排列数。
因此,我们可以生成n位数字的每个列表,检查它是否是一个排列,如果是,则增加一个计数器:
window.factorial = function($nb_number) {
$nb_trials = 1
for($i = 0; $i < $nb_number; $i++) $nb_trials *= $nb_number
$nb_successes = 0
__trying__:
for($nb_trial = 0; $nb_trial < $nb_trials; $nb_trial++){
$a_trial_split = new Array
$nb_tmp = $nb_trial
for ($nb_digit = 0; $nb_digit < $nb_number; $nb_digit++){
$a_trial_split[$nb_digit] = $nb_tmp - $nb_number * Math.floor($nb_tmp / $nb_number)
$nb_tmp = Math.floor($nb_tmp / $nb_number)
}
for($i = 0; $i < $nb_number; $i++)
for($j = 0; $j < $nb_number; $j++)
if($i != $j)
if($a_trial_split[$i] == $a_trial_split[$j])
continue __trying__
$nb_successes += 1
}
return $nb_successes
}
alert("input a number")
document.open()
document.write("<input type = text onblur = alert(factorial(parseInt(this.value))))>")
document.close()
巨魔:
O(n)
,不是O(n!)
,而是O(n^n)
。仅此一项就足以在这里有资格。number.toString(base)
,但是不适用于36以上的基数。是的,我知道36!是很多,但仍...Math.pow
?没有?那好吧。++
在for循环之外使用使它更加神秘。而且,==
是不好的。$i
。new Array
,document.write
(与朋友)和alert
(而不是一个提示或输入标记)形成的功能选择罪一个完整的三连胜。为什么毕竟要动态添加输入?=
使它们更难阅读。Ruby和WolframAlpha
该解决方案使用WolframAlpha REST API计算阶乘,RestClient提取解决方案,Nokogiri解析它。它不会重制任何轮子,而是使用经过良好测试和流行的技术以最现代的方式获得结果。
require 'rest-client'
require 'nokogiri'
n = gets.chomp.to_i
response = Nokogiri::XML(RestClient.get("http://api.wolframalpha.com/v2/query?input=#{n}!&format=moutput&appid=YOUR_APP_KEY"))
puts response.xpath("//*/moutput/text()").text
Javascript是一种功能编程语言,这意味着您必须对所有功能都使用函数,因为它的速度更快。
function fac(n){
var r = 1,
a = Array.apply(null, Array(n)).map(Number.call, Number).map(function(n){r = r * (n + 1);});
return r;
}
r = -~(function(){})
一定会解决这个问题。
public class Factorial {
public static void main(String[] args) {
//take the factorial of the integers from 0 to 7:
for(int i = 0; i < 8; i++) {
System.out.println(i + ": " + accurate_factorial(i));
}
}
//takes the average over many tries
public static long accurate_factorial(int n) {
double sum = 0;
for(int i = 0; i < 10000; i++) {
sum += factorial(n);
}
return Math.round(sum / 10000);
}
public static long factorial(int n) {
//n! = number of ways to sort n
//bogo-sort has O(n!) time, a good approximation for n!
//for best results, average over several passes
//create the list {1, 2, ..., n}
int[] list = new int[n];
for(int i = 0; i < n; i++)
list[i] = i;
//mess up list once before we begin
randomize(list);
long guesses = 1;
while(!isSorted(list)) {
randomize(list);
guesses++;
}
return guesses;
}
public static void randomize(int[] list) {
for(int i = 0; i < list.length; i++) {
int j = (int) (Math.random() * list.length);
//super-efficient way of swapping 2 elements without temp variables
if(i != j) {
list[i] ^= list[j];
list[j] ^= list[i];
list[i] ^= list[j];
}
}
}
public static boolean isSorted(int[] list) {
for(int i = 1; i < list.length; i++) {
if(list[i - 1] > list[i])
return false;
}
return true;
}
}
实际上,这非常缓慢,并且对于更高的数字并不准确。
佩尔
阶乘可能是一个难题。像Google一样,类似map / reduce的技术可以通过分叉一系列过程并收集结果来拆分数学。在寒冷的冬天晚上,这将充分利用系统中的所有这些核心或CPU。
另存为f.perl和chmod 755以确保可以运行它。您确实安装了病理折衷的垃圾清单,不是吗?
#!/usr/bin/perl -w
use strict;
use bigint;
die "usage: f.perl N (outputs N!)" unless ($ARGV[0] > 1);
print STDOUT &main::rangeProduct(1,$ARGV[0])."\n";
sub main::rangeProduct {
my($l, $h) = @_;
return $l if ($l==$h);
return $l*$h if ($l==($h-1));
# arghhh - multiplying more than 2 numbers at a time is too much work
# find the midpoint and split the work up :-)
my $m = int(($h+$l)/2);
my $pid = open(my $KID, "-|");
if ($pid){ # parent
my $X = &main::rangeProduct($l,$m);
my $Y = <$KID>;
chomp($Y);
close($KID);
die "kid failed" unless defined $Y;
return $X*$Y;
} else {
# kid
print STDOUT &main::rangeProduct($m+1,$h)."\n";
exit(0);
}
}
巨魔:
ARGV[0]
直到perl中的TIL 实际上是第一个参数,而不是脚本!
$ARGV[0]
因为大多数语言我知道一点有它存在
只需O(n!* n ^ 2)算法即可找到阶乘。处理基本情况。没有溢出。
def divide(n,i):
res=0
while n>=i:
res+=1
n=n-i
return res
def isdivisible(n,numbers):
for i in numbers:
if n%i!=0:
return 0
n=divide(n,i)
return 1
def factorial(n):
res = 1
if n==0: return 1 #Handling the base case
while not isdivisible(res,range(1,n+1)):
res+=1
return res
Well, there is an easy solution in Golfscript. You could use a Golfscript interpreter and run this code:
.!+,1\{)}%{*}/
Easy huh :) Good luck!
!
factorial[n_] := Length[Permutations[Table[k, {k, 1, n}]]]
It doesn't seem work for numbers larger than 11, and factorial[11] froze up my computer.
The correct approach for these difficult math problems is a DSL. So I'll model this in terms of a simple language
data DSL b a = Var x (b -> a)
| Mult DSL DSL (b -> a)
| Plus DSL DSL (b -> a)
| Const Integer (b -> a)
To write our DSL nicely, it's helpful to view it as a free monad generated by the algebraic functor
F X = X + F (DSL b (F X)) -- Informally define + to be the disjoint sum of two sets
We could write this in Haskell as
Free b a = Pure a
| Free (DSL b (Free b a))
I will leave it to the reader to derive the trivial implementation of
join :: Free b (Free b a) -> Free b a
return :: a -> Free b a
liftF :: DSL b a -> Free b a
Now we can descibe an operation to model a factorial in this DSL
factorial :: Integer -> Free Integer Integer
factorial 0 = liftF $ Const 1 id
factorial n = do
fact' <- factorial (n - 1)
liftF $ Mult fact' n id
Now that we've modeled this, we just need to provide an actual interpretation function for our free monad.
denote :: Free Integer Integer -> Integer
denote (Pure a) = a
denote (Free (Const 0 rest)) = denote $ rest 0
...
And I'll leave the rest of the denotation to the reader.
To improve readability, it's sometimes helpful to present a concrete AST of the form
data AST = ConstE Integer
| PlusE AST AST
| MultE AST AST
然后是微不足道的反思
reify :: Free b Integer -> AST
然后递归评估AST很简单。
factorial
例程的输入和输出,并在内部将字符串拆分为数字以执行乘法。
So here is the code: the getDigits
function splits a string representing a number in to its digits, so "1234" becomes [ 4, 3, 2, 1 ]
(the reverse order just makes the increase
and multiply
functions simpler). The increase
function takes such a list and increases it by one. As the name suggests, the multiply
function multiplies, e.g. multiply([2, 1], [3])
returns [ 6, 3 ]
because 12 times 3 is 36. This works in the same way as you would multiply something with pen and paper.
Then finally, the factorial
function uses these helper functions to calculate the actual factorial, for example factorial("9")
gives "362880"
as its output.
import copy
def getDigits(n):
digits = []
for c in n:
digits.append(ord(c) - ord('0'))
digits.reverse()
return digits
def increase(d):
d[0] += 1
i = 0
while d[i] >= 10:
if i == len(d)-1:
d.append(0)
d[i] -= 10
d[i+1] += 1
i += 1
def multiply(a, b):
subs = [ ]
s0 = [ ]
for bi in b:
s = copy.copy(s0)
carry = 0
for ai in a:
m = ai * bi + carry
s.append(m%10)
carry = m//10
if carry != 0:
s.append(carry)
subs.append(s)
s0.append(0)
done = False
res = [ ]
termsum = 0
pos = 0
while not done:
found = False
for s in subs:
if pos < len(s):
found = True
termsum += s[pos]
if not found:
if termsum != 0:
res.append(termsum%10)
termsum = termsum//10
done = True
else:
res.append(termsum%10)
termsum = termsum//10
pos += 1
while termsum != 0:
res.append(termsum%10)
termsum = termsum//10
return res
def factorial(x):
if x.strip() == "0" or x.strip() == "1":
return "1"
factorial = [ 1 ]
done = False
number = [ 1 ]
stopNumber = getDigits(x)
while not done:
if number == stopNumber:
done = True
factorial = multiply(factorial, number)
increase(number)
factorial.reverse()
result = ""
for c in factorial:
result += chr(c + ord('0'))
return result
print factorial("9")
In python an integer doesn't have a limit, so if you'd like to do this manually you can just do
fac = 1
for i in range(2,n+1):
fac *= i
There's also the very convenient math.factorial(n)
function.
This solution is obviously far more complex than it needs to be, but it does work and in fact it illustrates how you can calculate the factorial in case you are limited by 32 or 64 bits. So while nobody will believe this is the solution you've come up with for this simple (at least in Python) problem, you can actually learn something.
The most reasonable solution is clearly to check through all numbers until you find the one which is the factorial of the given number.
print('Enter the number')
n=int(input())
x=1
while True:
x+=1
tempx=int(str(x))
d=True
for i in range(1, n+1):
if tempx/i!=round(tempx/i):
d=False
else:
tempx/=i
if d:
print(x)
break
Every one knows the most elegant solutions to factorials are recursive.
Factorial:
0! = 1
1! = 1
n! = n * (n - 1)!
But multiplication can also be defined recursively as successive additions.
Multiplication:
n * 0 = 0
n * 1 = n
n * m = n + n * (m - 1)
And so can addition as successive incrementations.
加成:
n + 0 = n
n + 1 = (n + 1)
n + m = (n + 1) + (m - 1)
在C
,我们可以使用++x
和--x
处理原语(x + 1)
和(x - 1)
分别,所以我们的一切定义。
#include <stdlib.h>
#include <stdio.h>
// For more elegance, use T for the type
typedef unsigned long T;
// For even more elegance, functions are small enough to fit on one line
// Addition
T A(T n, T m) { return (m > 0)? A(++n, --m) : n; }
// Multiplication
T M(T n, T m) { return (m > 1)? A(n, M(n, --m)): (m? n: 0); }
// Factorial
T F(T n) { T m = n; return (m > 1)? M(n, F(--m)): 1; }
int main(int argc, char **argv)
{
if (argc != 2)
return 1;
printf("%lu\n", F(atol(argv[1])));
return 0;
}
让我们尝试一下:
$ ./factorial 0
1
$ ./factorial 1
1
$ ./factorial 2
2
$ ./factorial 3
6
$ ./factorial 4
24
$ ./factorial 5
120
$ ./factorial 6
720
$ ./factorial 7
5040
$ ./factorial 8
40320
完美,虽然8!由于某种原因花了很长时间。哦,最优雅的解决方案并不总是最快的。让我们继续:
$ ./factorial 9
嗯,等它回来时,我会告诉你...
正如@Matt_Sieker的回答所指出的那样,可以将阶乘分解为另外的部分-为什么,分解任务是编程的本质。但是,我们可以将其分解为1!
def complicatedfactorial(n):
def addby1(num):
return num + 1
def addnumbers(a,b):
copy = b
cp2 = a
while b != 0:
cp2 = addby1(cp2)
b -= 1
def multiply(a,b):
copy = b
cp2 = a
while b != 0:
cp2 = addnumbers(cp2,cp2)
if n == 0:
return 1
else:
return multiply(complicatedfactorial(n-1),n)
我认为这段代码可以保证出现SO错误,因为
递归-预热
每层都会产生调用以进行乘法
生成对addnumbers的调用
生成对addby1的调用!
功能太多了吧?
Let's try to do it by the Monte Carlo Method. We all know that the probability of two random n-permutations being equal is exactly 1/n!. Therefore we can just check how many tests are needed (let's call this number b) until we get c hits. Then, n! ~ b/c.
def RandomPermutation(n) :
t = range(0,n)
for i in xrange(n-1,0,-1):
x = t[i]
r = randint(0,i)
t[i] = t[r]
t[r] = x
return t
def MonteCarloFactorial(n,c) :
a = 0
b = 0
t = RandomPermutation(n)
while a < c :
t2 = list(t)
t = RandomPermutation(n)
if t == t2 :
a += 1
b += 1
return round(b/c)
MonteCarloFactorial(5,1000)
# returns an estimate of 5!
Factorials are easily determined with well known command line tools from bash.
read -p "Enter number: " $n
seq 1 $n | xargs echo | tr ' ' '*' | bc
As @Aaron Davies mentioned in the comments, this looks much tidier and we all want a nice and tidy program, don't we?
read -p "Enter number: " $n
seq 1 $n | paste -sd\* | bc
paste
command: seq 1 $n | paste -sd\* | bc
paste
does look like a regular English word and with that easy to remember. Do we really want that? ;o)