正数の階乗を見つけるにはどうすればよいですか?


18

チャレンジ:

正数を入力してその階乗を返すプログラムまたは関数を作成します。

注:これは質問です。質問や回答を真剣に受け取らないでください。詳細はこちら。すべての質問は質問でもあるため、最も多く投票された回答が勝ちます。



4
-1、申し訳ありませんが、我々はこれらのコードトローリング質問の巨大な洪水を取得しているので、これは本当に彼らに何か新しいものを追加していません
ドアノブ


公式のスタンスに従ってコードトローリングは削除される過程にあります。この質問にはかなりの票があり、多くの回答がありますが、その多くは非常に高く投票されています。投票で50%を超える "削除"票を獲得しましたが、非常に多くの回答と票を獲得したという点でユニークであるため、歴史的な重要性のためにロックしています。
ドアノブ

回答:


46

これは非常に単純な数値計算問題であり、スターリングの近似で解決できます

Stirling's approximation formula

ご覧のとおり、この式は平方根を特徴としていますが、これを近似する方法も必要です。それは、おそらく最も単純な方法であるため、いわゆる「バビロニア法」を選択します。

Babylonian method

この方法で平方根を計算することは、再帰の良い例です。

すべてを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

この方法は、ほとんどのアプリケーションで十分に正確でなければなりません。


16
1この方法の単純さと正確さがそれ明確な勝者になる
ジョー・パーソン

44

C#

申し訳ありませんが、再帰関数は嫌いです。

public string Factorial(uint n) {
    return n + "!";
}

1
技術的には、簡単な説明に満足しています!;)短時間の悪用+1
WallyWest 14年

36

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();
}
}

16
私はそれを試しました-非常に効率的です。次のリリースで出荷されます。:)
ヨハネス

「魔法の数のシンドローム」に加えて、これは実際にはn <13であり、スタックがはるかに少ない限り、適切な実装になります。「ケース4:return 4 * 3 * 2;」と書きます。そして、あなたはまともなクラスを持っているでしょう、古い再帰的なクラスよりもはるかに高速です。
Fabinout

6
@ Fabinout、n> = 13でも実装は正しい。13!> Integer.MAX_VALUE。
エモリー14年

21

Python

もちろん、問題を解決する最良の方法は、正規表現を使用することです。

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)

1
もちろん確かに:)
ピエールアラード14年

15

ハスケル

短いコードは効率的なコードなので、これを試してください。

fac = length . permutations . flip take [1..]

トローリングする理由:

私はこれを書いたコーダーを笑います...非効率性は美しいです。また、実際に階乗関数を書くことができないHaskellプログラマには理解できないでしょう。

編集:私はこれを少し前に投稿しましたが、将来の人々とHaskellを読むことができない人々のために明確にしたいと思いました。

ここのコードは、1からnまでの数字のリストを受け取り、そのリストのすべての順列のリストを作成し、そのリストの長さを返します。私のマシンでは、13分で約20分かかります。そして、それは14時間で4時間かかるはずです!そして、15日間2日半!そこのある時点でメモリ不足になることを除いて。

編集2:実際には、これがHaskellであるためにメモリを使い果たすことはおそらくないでしょう(以下のコメントを参照)。リストを評価してメモリに保持するように強制することもできますが、Haskellを最適化(および非最適化)する方法について正確に知ることはできません。


恐ろしいと同時にエレガントな、すべて同時に。
PLL 14年

1
メモリの問題について確かですか?どの時点でも、メモリを保持する必要があります:-リスト[1..n]。-の特定の順列は[1..n]、残りの順列のサンクに限定されています(多項式n)。- length関数のアキュムレーター。
ジョン・ドヴォルザーク

公正な点、おそらく実際にはそうではありません。あまり考えすぎませんでした。下部にコメントを追加します。
jgon

10

C#

これは数学の問題であるため、数学の問題を解決するために特別に設計されたアプリケーションを使用してこの計算を行うことは理にかなっています...

ステップ1:

MATLABをインストールします。試用版は機能すると思いますが、この非常に複雑な問題は、アプリケーションのフルバージョンを購入するに値するほど重要です。

ステップ2:

アプリケーションにMATLAB COMコンポーネントを含めます。

ステップ3:

public string Factorial(uint n) {
    MLApp.MLApp matlab = new MLApp.MLApp();
    return matlab.Execute(String.Format("factorial({0})", n);
}

学生向けMatlabは100ドルからです。プロフェッショナルバージョンまたはサイトライセンスは数千に及ぶ場合があります。
モシェカッツ

4
モシェ・カッツ-階乗なので正当化。
マイクH. 14年

9

C#

階乗は、一度にすべてを消化するのが難しい場合がある高レベルの数学演算です。このようなプログラミング問題の最善の解決策は、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;
    }
}

これをすべて1つのCPUまたはコアを介して送信するボトルネックがあります。これは私の答えで解決できたと思います:
Paul

9
#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;
}

トロール:

  • 階乗を計算する100%正しい方法で、反復的または再帰的に実行するポイントを完全に逃します。
  • なぜそれが機能するのか分かりませんし、他のことをするために一般化することもできません。
  • 整数演算で計算するよりもコストがかかります。
  • 最も明らかな「準最適」コード(z = n - 1 + 1)は、何が起こっているかを知っている場合、実際には自己文書化です。
  • 余分なトローリングについてp[]は、シリーズ係数の再帰計算を使用して計算する必要があります!

(これは、ガンマ関数のランチョス近似です


- 1 + 1ここに何かポイントはありますか?私のコンパイラはそれを最適化します(このようなコードの最適化が危険になる可能性があるのは浮動小数点数ではないため)。
コンラッドボロウスキ

4
@xfix:double z = n - 1ガンマ関数の近似の一部です。これ+ 1は、gamma(n + 1) = n!整数nの関係からです。
ベンジャクソン

9

大学では、乗算を計算する最も効率的な方法は対数を使用することであることを誰もが知っています。結局、何百年もの間、他の人が対数表を使用するのはなぜですか?

そのため、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が悪いので)。これが上記の機能が必要な理由です。

ところで、学生のための一般的なヒントは、何かが期待どおりに機能しない場合、おそらく言語が悪いからだということです。


私は説明のためにそこに余分な投票をすることができればいいのですが、Pythonは嫌です
マークKコーワン

1
私は「FACあなた」で笑った
Number9

8

残念ながら、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()


トロール:

  • ハンガリー記法、snake_case 不要なシギルを入力します。それはどれほど悪ですか?
  • ジャンプラベルの独自の規則を考案しましたが、この規則の現在の使用とは互換性がありません。
  • 考えられるすべての変数は、誤ってグローバルです。
  • 解決策はないがO(n)、ないO(n!)、しかしO(n^n)。ここで資格を得るにはこれだけで十分でしょう。
  • 数値をインクリメントしてからbase-nに変換することは、シーケンスのリストを生成するのに悪い方法です。たとえ複製が必要だったとしても。n> 13の場合に神秘的に壊れるだけが理由ではありません。
  • もちろんを使用することもできますnumber.toString(base)が、36を超えるベースでは機能しません。はい、36を知っています!ある多くは、まだ、...
  • Javascriptにはモジュラス演算子がありますか?またはMath.pow?番号?しかたがない。
  • ++forループ以外での使用を拒否すると、さらに不思議になります。また、==悪いです。
  • 深くネストされたブレースレスループ構造。また、ANDの代わりにネストされた条件。また、内側のループをで終了することにより、外側の条件を回避できました$i
  • 機能new Arraydocument.write(友人と)及びalert(代わりに、プロンプトまたは入力ラベルの)は、機能選択罪の完全な三連勝単式を形成します。結局、入力が動的に追加されるのはなぜですか?
  • インラインイベントハンドラー。ああ、そして深い配管はデバッグするのが大変だ。
  • 引用符で囲まれていない属性は楽しいものであり、周囲にスペース=があると読みにくくなります。
  • 私はすでにセミコロンが嫌いだと言いましたか?

8

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

7

Javascript

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;
}

1
説明できる?
Mhmd

7
1は関数ではありません。したがって、コードは遅くなります。
ピエールアラード14年

4
@ArlaudPierre r = -~(function(){})はそれを確実に解決します。
nitro2k01

4
私は仕事用のマシンにいるので、この言語をインストールしたくありません。ブラウザで実行されるバージョンはどこにありますか?
joeytwiddle

3
上司がアカウントを持っているため、Googleを使用するのが少し怖いです。職場でゴルフをしていることを上司に知らせたくありません。Javascriptを実行できるFirefoxの拡張機能を探していましたが、見つからないようです。私の友人の何人かはjsfiddle.netでJavascriptを実行していますが、それは他人の電気を使用しているため、盗みに似ています。私の母は、私はそのような人々と一緒にいるべきではないと言ったが、彼らは私の友人であるので、私は何ができますか?とにかく彼女は時々彼女が必要とするより多くのクリームを取る。ヒントをありがとう、FirefoxでCtrl-Shift-JまたはKを使用します。免責事項:#comment-
trolling

5

JavaでのBogo-Sortの使用

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;
    }
}

これは実際には非常にゆっくりと動作しますが、数値が大きい場合は正確ではありません。


4

パー

階乗は難しい問題です。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);
    }
}

トロール:

  • O(log2(N))プロセスをフォークします
  • CPUまたはコアの数をチェックしません
  • すべてのプロセスで発生する多くのbigint / text変換を隠します
  • 多くの場合、forループはこのコードよりも高速です

TILはperl ARGV[0]では実際にはスクリプトではなく最初の引数です!
ThinkChaos 14年

@plg私は$ 0は、スクリプトのファイル名が含まれているかもしれませんが、それは$ ARGV [0]と同じではありません信じて
ポール

うん、それは私が読んだものです。私はちょうどそれがperlでそれはないことは驚くべき発見$ARGV[0]私は少し知っているほとんどの言語がそれを持っているので
ThinkChaos

4

Python

階乗を見つけるための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

3

Golfscriptには簡単な解決策があります。Golfscriptインタープリターを使用して、次のコードを実行できます。

.!+,1\{)}%{*}/

簡単だね:)がんばって!


2
私はGolfScriptを知りませんが、これは私を失望させます...このサイトの他のGolfScriptの例に基づいて、答えは次のようになると予想していました!
ミスターリスター14年

1
それが否定演算子です。0が1になり、他のすべてが0になる
マルタインCourteaux


3

ルビー

f=->(n) { return 1 if n.zero?; t=0; t+=1 until t/n == f[n-1]; t }

私が想像できる最も遅いワンライナー。i7プロセッサで計算するには2分かかります6!


2

これらの難しい数学の問題に対する正しいアプローチは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を再帰的に評価するのは簡単です。


2

Python

以下はPythonバージョンのソリューションです。これは、Pythonの整数の32ビット(ごく最近のシステムでは64ビット)の制限に制限されていません。この制限を回避するには、factorialルーチンの入力および出力として文字列を使用し、乗算を実行できるようにその文字列をその数字で内部的に分割します。

コードは次のとおりです。getDigits関数は、数値を表す文字列をその数字に分割します。したがって、「1234」になります[ 4, 3, 2, 1 ](逆の順序では、関数increasemultiply関数が単純になります)。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の)問題に対してあなたが思いついた解決策であるとは誰も信じないでしょうが、実際に何かを学ぶことができます。


Pythonには整数値に制限はありません...そうですか?これをもっとよく説明する必要があるかもしれません。
ライキング

@Rikingはい、Pythonでは整数に制限はありません。より明確にするために、いくつかのメモを追加しました。
brm

2

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

2

Cで最もエレガントな再帰的ソリューション

階乗の最もエレガントな解決策が再帰的であることは誰もが知っています。

階乗:

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

うーん、戻ってきたらお知らせします...


2

Python

@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エラーを保証すると思う

  1. 再帰-ウォームアップ

  2. 各層は乗算する呼び出しを生成します

  3. addnumbersの呼び出しを生成します

  4. addby1!の呼び出しを生成します

機能が多すぎますか?



1

TIベーシック84

:yumtcInputdrtb@gmail And:cReturnbunchojunk@Yahoo A!op:sEnd:theemailaddressIS Crazy ANSWER LOL

それは実際に動作します :)


1

Javascript

明らかにプログラマの仕事は、できる限り少ない作業を行い、できるだけ多くのライブラリを使用することです。したがって、jQuery math.jsをインポートます。これで、タスクは次のように簡単になりました。

$.alert=function(message){
    alert(message);
}$.factorial=function(number){
    alert(math.eval(number+"!"));
    return math.eval(number+"!");
}
$.factorial(10);

1

Python

標準の再帰的階乗の実装をわずかに変更するだけで、n> 10の場合、許容できないほど遅くなります。

def factorial(n):
    if n in (0, 1):
        return 1
    else:
        result = 0
        for i in range(n):
            result += factorial(n - 1)
        return result

1

バッシュ

#! /bin/bash

function fact {
    if [[ ${1} -le 1 ]]; then
        return 1
    fi;

    fact $((${1} - 1))
    START=$(date +%s)
    for i in $(seq 1 $?); do sleep ${1}; done
    END=$(date +%s)
    RESULT=$(($END - $START))
    return $RESULT
}

fact ${1}
echo $?

1

モンテカルロ法でやってみましょう。私たちは皆、2つのランダムなn順列が等しい確率が正確に1 / nであることを知っています!。したがって、c個のヒットが得られるまで、必要なテストの数を確認するだけです(この番号をbと呼びましょう)。次に、n!〜b / c

セージ、Pythonでも動作するはずです

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!

1

バッシュ

階乗は、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

1
私は非常に過小評価さ-お勧めしますpaste:コマンドseq 1 $n | paste -sd\* | bc
アーロン・デイヴィス

2
@AaronDavies pasteは、通常の英語の単語のように見え、覚えやすいです。本当にそれが必要ですか?; o)
ジッピー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.