チャレンジ:
正数を入力してその階乗を返すプログラムまたは関数を作成します。
注:これはコードトローリングの質問です。質問や回答を真剣に受け取らないでください。詳細はこちら。すべてのコードトローリングの質問は人気コンテストの質問でもあるため、最も多く投票された回答が勝ちます。
チャレンジ:
正数を入力してその階乗を返すプログラムまたは関数を作成します。
注:これはコードトローリングの質問です。質問や回答を真剣に受け取らないでください。詳細はこちら。すべてのコードトローリングの質問は人気コンテストの質問でもあるため、最も多く投票された回答が勝ちます。
回答:
これは非常に単純な数値計算問題であり、スターリングの近似で解決できます。
ご覧のとおり、この式は平方根を特徴としていますが、これを近似する方法も必要です。それは、おそらく最も単純な方法であるため、いわゆる「バビロニア法」を選択します。
この方法で平方根を計算することは、再帰の良い例です。
すべてを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 string Factorial(uint n) {
return n + "!";
}
Java
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までの数字のリストを受け取り、そのリストのすべての順列のリストを作成し、そのリストの長さを返します。私のマシンでは、13分で約20分かかります。そして、それは14時間で4時間かかるはずです!そして、15日間2日半!そこのある時点でメモリ不足になることを除いて。
編集2:実際には、これがHaskellであるためにメモリを使い果たすことはおそらくないでしょう(以下のコメントを参照)。リストを評価してメモリに保持するように強制することもできますが、Haskellを最適化(および非最適化)する方法について正確に知ることはできません。
[1..n]
。-の特定の順列は[1..n]
、残りの順列のサンクに限定されています(多項式n
)。- length
関数のアキュムレーター。
これは数学の問題であるため、数学の問題を解決するために特別に設計されたアプリケーションを使用してこの計算を行うことは理にかなっています...
MATLABをインストールします。試用版は機能すると思いますが、この非常に複雑な問題は、アプリケーションのフルバージョンを購入するに値するほど重要です。
アプリケーションにMATLAB COMコンポーネントを含めます。
public string Factorial(uint n) {
MLApp.MLApp matlab = new MLApp.MLApp();
return matlab.Execute(String.Format("factorial({0})", n);
}
階乗は、一度にすべてを消化するのが難しい場合がある高レベルの数学演算です。このようなプログラミング問題の最善の解決策は、1つの大きなタスクを小さなタスクに分割することです。
今、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[]
は、シリーズ係数の再帰計算を使用して計算する必要があります!- 1 + 1
ここに何かポイントはありますか?私のコンパイラはそれを最適化します(このようなコードの最適化が危険になる可能性があるのは浮動小数点数ではないため)。
double z = n - 1
ガンマ関数の近似の一部です。これ+ 1
は、gamma(n + 1) = n!
整数nの関係からです。
大学では、乗算を計算する最も効率的な方法は対数を使用することであることを誰もが知っています。結局、何百年もの間、他の人が対数表を使用するのはなぜですか?
そのため、IDから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;
}
}
これは実際には非常にゆっくりと動作しますが、数値が大きい場合は正確ではありません。
パー
階乗は難しい問題です。map / reduceのようなテクニックは、Googleが使用するのと同じように、多数のプロセスを分岐して結果を収集することにより、数学を分割できます。これにより、寒い冬の夜にシステムのすべてのコアまたはCPUを有効に活用できます。
f.perlおよびchmod 755として保存して、実行できることを確認します。Pathologically Eclectic Rubbish Listerはインストールされていますか?
#!/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]
では実際にはスクリプトではなく最初の引数です!
$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
Golfscriptには簡単な解決策があります。Golfscriptインタープリターを使用して、次のコードを実行できます。
.!+,1\{)}%{*}/
簡単だね:)がんばって!
!
factorial[n_] := Length[Permutations[Table[k, {k, 1, n}]]]
11より大きい数値では機能しないようで、階乗[11]でコンピューターがフリーズしました。
これらの難しい数学の問題に対する正しいアプローチはDSLです。単純な言語の観点からこれをモデル化します
data DSL b a = Var x (b -> a)
| Mult DSL DSL (b -> a)
| Plus DSL DSL (b -> a)
| Const Integer (b -> a)
DSLをうまく書くために、代数的ファンクターによって生成された無料のモナドとしてそれを見ると便利です
F X = X + F (DSL b (F X)) -- Informally define + to be the disjoint sum of two sets
Haskellで次のように書くことができます。
Free b a = Pure a
| Free (DSL b (Free b a))
私はそれを読者に任せて、ささいな実装を導き出します。
join :: Free b (Free b a) -> Free b a
return :: a -> Free b a
liftF :: DSL b a -> Free b a
これで、このDSLで階乗をモデル化する操作を説明できます。
factorial :: Integer -> Free Integer Integer
factorial 0 = liftF $ Const 1 id
factorial n = do
fact' <- factorial (n - 1)
liftF $ Mult fact' n id
これをモデル化したので、無料のモナドの実際の解釈関数を提供するだけです。
denote :: Free Integer Integer -> Integer
denote (Pure a) = a
denote (Free (Const 0 rest)) = denote $ rest 0
...
そして、残りの表示は読者に任せます。
読みやすくするために、次の形式の具体的なASTを提示すると役立つ場合があります
data AST = ConstE Integer
| PlusE AST AST
| MultE AST AST
そして、ささいな反射を右
reify :: Free b Integer -> AST
ASTを再帰的に評価するのは簡単です。
factorial
ルーチンの入力および出力として文字列を使用し、乗算を実行できるようにその文字列をその数字で内部的に分割します。
コードは次のとおりです。getDigits
関数は、数値を表す文字列をその数字に分割します。したがって、「1234」になります[ 4, 3, 2, 1 ]
(逆の順序では、関数increase
とmultiply
関数が単純になります)。increase
この関数は、このようなAリストと1ずつ増加それを取ります。名前が示すように、multiply
関数は乗算します。たとえば、12の3が36であるため、multiply([2, 1], [3])
戻ります[ 6, 3 ]
。これは、ペンと紙で何かを乗算するのと同じように機能します。
最後に、factorial
関数はこれらのヘルパー関数を使用して実際の階乗を計算します。たとえば、出力としてfactorial("9")
与え"362880"
ます。
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")
Pythonでは整数には制限がありませんので、手動でこれをしたい場合は
fac = 1
for i in range(2,n+1):
fac *= i
非常に便利なmath.factorial(n)
機能もあります。
このソリューションは、明らかに必要以上に複雑ですが、実際には機能し、実際、32ビットまたは64ビットに制限されている場合に階乗を計算する方法を示しています。したがって、これがこの単純な(少なくともPythonの)問題に対してあなたが思いついた解決策であるとは誰も信じないでしょうが、実際に何かを学ぶことができます。
最も合理的な解決策は、特定の数値の階乗である数値が見つかるまで、すべての数値を確認することです。
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
階乗の最もエレガントな解決策が再帰的であることは誰もが知っています。
階乗:
0! = 1
1! = 1
n! = n * (n - 1)!
ただし、乗算は、連続した加算として再帰的に定義することもできます。
乗算:
n * 0 = 0
n * 1 = n
n * m = n + n * (m - 1)
そして、連続した増分として追加できます。
添加:
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!の呼び出しを生成します
機能が多すぎますか?
モンテカルロ法でやってみましょう。私たちは皆、2つのランダムなn順列が等しい確率が正確に1 / nであることを知っています!。したがって、c個のヒットが得られるまで、必要なテストの数を確認するだけです(この番号をbと呼びましょう)。次に、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!
階乗は、bashのよく知られているコマンドラインツールで簡単に決定できます。
read -p "Enter number: " $n
seq 1 $n | xargs echo | tr ' ' '*' | bc
@Aaron Daviesがコメントで言及したように、これはかなりきれいに見え、私たちは皆、きちんとしたきれいなプログラムを望んでいますよね?
read -p "Enter number: " $n
seq 1 $n | paste -sd\* | bc
paste
:コマンドseq 1 $n | paste -sd\* | bc
paste
は、通常の英語の単語のように見え、覚えやすいです。本当にそれが必要ですか?; o)