階乗の逆数を計算する


30

入力として1より大きい実数を取り、その正の逆階乗を出力する最短コードを記述します。つまり、「この数に等しい階乗の数」という質問に答えます。ここで説明するように、ガンマ関数を使用して、階乗の定義を任意の実数に拡張します

例えば:

input=6 output=3 
input=10 output=3.390077654

理由3! = 63.390077654! = 10

ルール

  • 組み込みの階乗関数またはガンマ関数、またはこれらの関数に依存する関数の使用は禁止されています。
  • プログラムは、任意の精度で計算できる理論上の能力を使用して、5桁の10進数で計算できる必要があります(任意の精度を得るために、任意の大小にできる数値を含む必要があります)
  • 任意の言語が許可され、文字の最短コードが優先されます。

ここで実例を作成しまし。ご覧ください。


2
これは、特にゼロと負の入力をカバーするために、さらにいくつかのテストケースを使用できます。
ピーターテイラー14年

入力が1より大きくなるように編集しました。そうしないと、複数の回答が存在する可能性があります。
イェンスレンダリング14年

1
あなたはまた、出力が1より大きくなければならないことを要件を追加しない限り、とにかく複数回答がある場合もあります
ピーター・テイラー

24を入力すると、実例では3.99999になります。そのような解決策は受け入れられますか?
ルービック14年

はい、これは小数点以下4桁から5桁の正しい位置と
見なす

回答:


13

Javascript(116)

ここに黒魔術!数ミリ秒で結果が得られます
使用された基本的な数学関数のみ:lnpowexponential

x=9;n=prompt(M=Math);for(i=1e4;i--;)x+=(n/M.exp(-x)/M.pow(x,x-.5)/2.5066/(1+1/12/x+1/288/x/x)-1)/M.log(x);alert(x-1)

残念ラテックスはcodegolfではサポートされていませんが、基本的に、私はコード化されたニュートンソルバーをf(y)=gamma(y)-n=0し、x=y-1(いるためx!であるgamma(x+1))、ガンマとディガンマ機能のための近似値。

ガンマ近似であるスターリング近似
ディガンマ近似用オイラーマクラウリン式を
。ジガンマ関数は、ガンマ関数をガンマ関数で除算したものです。f'(y)=gamma(y)*digamma(y)

アンゴルフド:

n = parseInt(prompt());
x = 9; //first guess, whatever but not too high (<500 seems good)

//10000 iterations
for(i=0;i<10000;i++) {

  //approximation for digamma
  d=Math.log(x);

  //approximation for gamma
  g=Math.exp(-x)*Math.pow(x,x-0.5)*Math.sqrt(Math.PI*2)*(1+1/12/x+1/288/x/x);

  //uncomment if more precision is needed
  //d=Math.log(x)-1/2/x-1/12/x/x+120/x/x/x/x;
  //g=Math.exp(-x)*Math.pow(x,x-0.5)*Math.sqrt(Math.PI*2)*(1+1/12/x+1/288/x/x-139/51840/x/x/x);

  //classic newton, gamma derivative is gamma*digamma
  x-=(g-n)/(g*d);
}

alert(x-1);

テストケース:

10 => 3.390062988090518
120 => 4.99999939151027
720 => 6.00000187248195
40320 => 8.000003557030217
3628800 => 10.000003941731514

それaltough非常に素晴らしい答えが必要な精度を満たしていないと、それだけで706未満の数値のために働く
イェンスはレンダリング

@JensRendersは、ニュートンソルバーの反復をいくつか追加し、初期推測を変更し、ガンマ関数のより良い近似を変更しました。これでルールに適合します。大丈夫なら今私に聞かせてください:)
マイケルM. 14年

はい、今は完璧です、私はそれを投票しました:)
ジェンスレンダーズ14年

1
あなたは、1つの文字を救うことができる:n=prompt(M=Math)
フロラン

こうした$ 10 ^ {10 ^ 6} $、そしてあなたは、整数の結果を得ることを確実にすることなど、多くのあなたのコードを実行してみてください
デイヴィッドG.ストーク

13

Mathematica- 74 54 49

適切な方法は

f[x_?NumberQ]:=NIntegrate[t^x E^-t,{t,0,∞}]
x/.FindRoot[f@x-Input[],{x,1}]

テストをドロップするだけ?NumberQでも動作しますが、いくつかの厄介な警告をスローします。これは、シンボリック統合Integrateに切り替えると消えますが、関数は自動的にGamma関数に変換されるため、これは違法です(と思われます)。また、そのようにして外部関数を取り除くこともできます。

とにかく

x/.FindRoot[Integrate[t^x E^-t,{t,0,∞}]-Input[],{x,1}]

適切な入力を行うには、関数定義のみ(MatLabに勝つことはできません)

x/.FindRoot[Integrate[t^x E^-t,{t,0,∞}]-#,{x,1}]&

組み込み階乗が許可された場合

N@InverseFunction[#!&]@Input[]

上記は整数を与えません(これは真の階乗関数の引数です)。以下は:

Floor[InverseFunction[Gamma][n]-1]

ああ、これらすべての組み込み関数!同様の方法を除いて、これは勝てるとは思いません。
ルービック14年

4
Mathematicaは数学の分野では非常に不公平です!:D
マイケルM. 14年

1
名前自体からMATHematica-
ダダン

されたNumberQパターンのテストが必要?または括弧でE^(-t)?それがオンに浮気されるNIntegrateIntegrate?おそらく... :)
オリオン14年

それは本当の挑戦に変わりつつあります;)
mmumboss 14年

6

ised: 72 46文字

これはほぼ完璧にフィットします...数学のゴルフのために正確に意図されているように見える「言語」があります:ised。その難読化された構文により、非常に短いコードが作成されます(名前付き変数はなく、整数のメモリスロットと、多用途の単一文字演算子が多数あります)。積分を使用してガンマ関数を定義すると、80のランダムな文字になりました

@4{:.1*@+{@3[.,.1,99]^x:*exp-$3}:}@6{:@{$4::@5avg${0,1}>$2}$5:}@0,0@1,99;$6:::.

ここで、メモリスロット$ 4は階乗関数であり、メモリスロット$ 6は二分関数であり、メモリスロット$ 2は入力に設定されると予想されます(このコードをソースする前に与えられます)。スロット$ 0および$ 1は、二分境界です。呼び出し例(上記のコードがfileにあると仮定inversefactorial.ised

bash> ised '@2{556}' --f inversefactorial.ised
556
5.86118

もちろん、ビルトインを使用することもできます!演算子。この場合、45文字まで取得できます。

@6{:@{{@5avg${0,1}}!>$2}$5:}@0,0@1,99;$6:::.

慎重に、オペレーターの優越性は時々奇妙です。

編集:関数を保存する代わりにインライン化することを忘れないでください。72文字でMathematicaを打ち負かす!

@0,0@1,99;{:@{{:.1*@+{@3[.,.1,99]^x:*exp-$3}:}::@5avg${0,1}>$2}$5:}:::.

そして!組み込みで41が得られます。


1年延滞の更新:

これは非常に非効率的であることに気づきました。60文字までゴルフダウン:

@0#@1,99;{:@{.1*@3[.,.1,99]^@5avg${0,1}@:exp-$3>$2}$5:}:::.

utf-8が使用されている場合(Mathematicaも同様)、57に到達します。

@0#@1,99;{:@{.1*@3[.,.1,99]^@5avg${0,1}·exp-$3>$2}$5:}∙.

少し異なる書き換えにより、46(または組み込み!を使用している場合は27)に削減できます。

{:x_S{.5@3[.,.1,99]^avgx·exp-$3*.1<$2}:}∙∓99_0

答えを2回印刷しても問題ない場合は、最後の2文字を削除できます。


私は誰かがこのビート見るならば、私は驚いされます:Oを
イェンスはレンダリング

@JensRenders:私はちょうどやった;)
mmumboss 14年

精度に関する議論を明確にするために、それは.1(統合ステップ)と99(統合制限)によって設定されます。分割は機械の精度になります。上記の数値(99!)を入力する場合を除き、@ 1,99の2分割制限を99に保つことができます。
オリオン

@mmumbossがまたお会いしました:)
オリオン

5

MATLAB 54 47

適切な課題を選択した場合、MATLABはゴルフに最適です:)。私のコードでは、uがユーザー入力、xが解く変数である方程式(ux!)= 0の解を見つけます。これは、u = 6がx = 3などにつながることを意味します...

@(x)fsolve(@(y)u-quad(@(x)x.^y./exp(x),0,99),1)

精度は、99に設定されている積分の上限を変更することで変更できます。これを下げると、出力の精度が次のように変わります。たとえば、10の入力の場合:

upper limit = 99; answer = 3.390077650833145;
upper limit = 20; answer = 3.390082293675363;
upper limit = 10; answer = 3.402035336604546;
upper limit = 05; answer = 3.747303578099607;


これはルールで必要とされるため、精度のオプションを指定する必要があります!「任意の精度を得るために、任意の大きいまたは小さいものにすることができる数を含める必要があります」
ジェンズレンダー14年

isedおよびMathematicaソリューションにも表示されませんか?しかし、私はそれを見ていきます。
mmumboss 14年

1
私はisedバージョンで番号99を参照してください、とMathematicaのバージョンがとにかく打たれる
イェンスはレンダリング

コード内の位置を考えると、これはおそらく積分の上限です。私のコードではこれはinfです。ええ、このinfを99に変更すると、私の答えの精度が低下します。つまり、この数値は精度に影響を与えるため、ルールを満たします。99に変更すると、charも保存されます;)
mmumboss 14年

しかし、infを99に変更した後、必要な精度を満たしますか?
ルービック14年

3

Python-199文字

わかりましたので、あなたは多くのスタックスペースと多くの時間を必要とします、しかし、ちょっと、それはそこに着くでしょう!

from random import *
from math import e
def f(x,n):
    q=randint(0,x)+random()
    z=0
    d=0.1**n
    y=d
    while y<100:
            z+=y**q*e**(-y)*d
            y+=d
    return q if round(z,n)==x else f(x,n)

さらに再帰を使用した別のアプローチを示します。

from random import *
from math import e
def f(x,n):
    q=randint(0,x)+random()
    return q if round(h(q,0,0.1**n,0),n)==x else f(x,n)
def h(q,z,d,y):
    if y>100:return z
    else:return h(q,z+y**q*e**(-y)*d,d,y+d)

これらは両方ともテストできます >>>f(10,1)再帰制限を10000前後に設定すれば。小数点以下1桁以上の精度は、現実的な再帰制限では完了しない可能性があります。

199文字までのコメントといくつかの修正を組み込みます。

from random import*
from math import*
def f(x,n):
    q=random()*x+random()
    z=y=0
    while y<100:
            z+=y**q*e**-y*0.1**n
            y+=0.1**n
    return q if round(z,n)==x else f(x,n)

2
これはcode-golf質問なので、ソリューションの長さを示す最短の回答を提供する必要があります。
ビジョン

良い方法ですが、問題は、これが答えを見つけることを保証できないことです...また、これは、キャラクターの使用を最小限に抑えようとするcodegolf zoです。
イェンスレンダリング14年

1
Pythonのrandom()はMersenne Twisterを使用しますが、これはPythonのフロートの空間を歩いていると考えられるため、許容範囲内に答えがあれば常に終了するはずです。
intx13

1つを繰り返す前にすべてのフロート値を返すという意味ですか?その場合、スタックオーバーフローを克服できる場合、このコードは有効です
イェンスはレンダリング

2
コードは可能です。あなたと私にはそれを実行する時間もコンピュータリソースもないかもしれません;)
intx13

3

Pythonの2.7 - 215の 189文字

f=lambda t:sum((x*.1)**t*2.71828**-(x*.1)*.1for x in range(999))
n=float(raw_input());x=1.;F=0;C=99
while 1:
 if abs(n-f(x))<1e-5:print x;break
 F,C,x=f(x)<n and(x,C,(x+C)/2)or(F,x,(x+F)/2)

使用法:

# echo 6 | python invfact_golf.py
2.99999904633
# echo 10 | python invfact_golf.py
3.39007514715
# echo 3628800 | python invfact_golf.py
9.99999685376

精度を変更するには、精度を上げる1e-5には小さい数値に、精度を下げるには大きい数値に変更します。より良い精度を得るには、おそらくにより良い値を与えたいでしょうe

これは、階乗関数をとして実装するだけfで、入力の逆数の最も正確な値に焦点を合わせるためにバイナリ検索を実行します。回答が99以下であると仮定します(365の回答では確かに機能しません。数学オーバーフローエラーが発生します)。非常に合理的なスペースと時間の使用、常に終了します。

または、で置換if abs(n-f(x))<=10**-5: print x;breakprint x50文字を削除します。それは永遠にループし、より正確な見積もりを提供します。ただし、これがルールに適合するかどうかはわかりません。


私はそのサイトが文字を数えることを知りませんでした。私は常に使用しますcat file | wc -c
ルービック14年

@rubik:いいね、それを使うとは思わなかった。両方とも一致=)
Claudiu 14年

2

dg - 131 133バイト

o,d,n=0,0.1,float$input!
for w in(-2..9)=>while(sum$map(i->d*(i*d)**(o+ 10**(-w))/(2.718281**(i*d)))(0..999))<n=>o+=10**(-w)
print o

dgはCPythonバイトコードを生成するため、これもPythonにカウントされるはずですが、ああ...いくつかの例:

$ dg gam.dg 
10
3.3900766499999984
$ dg gam.dg 
24
3.9999989799999995
$ dg gam.dg 
100
4.892517629999997
$ dg gam.dg 
12637326743
13.27087070999999
$ dg gam.dg  # i'm not really sure about this one :P it's instantaneous though
28492739842739428347929842398472934929234239432948923
42.800660880000066
$ dg gam.dg  # a float example
284253.232359
8.891269689999989

編集:2バイトを追加しました。フロートも受け入れる必要があることを覚えていなかったからです!


私が与える42.8006566063ので、5桁の精度内で一致します!
Claudiu 14年

それは素晴らしいことです!上限がどこにあるかはわかりませんが、どこかで壊れるはずです。以下の場合1e100:それは与え69.95780520000001、ために1e150それが出力96.10586423000002用のに対し、1e200それが吹きます。しかし、実際に私は、これらの結果は...信頼性があるかどうかわからない
ルービック

1

R、92バイト

関数、g入力zを受け取り、その数の逆階乗を出力します

これからゴルフをすることはほぼ間違いなくありますので、私が改善できるものを見つけたら、私に知らせてください。

library(pryr)
g=f(z,uniroot(f(a,integrate(f(x,x^a*exp(-x)),0,Inf)$v-z),c(0,z+1),tol=1e-9)$r)

オンラインでお試しください!

非ゴルフとコメント

library(pryr)                     # Add pryr to workspace
inv.factorial = f(z,              # Declare function which  
  uniroot(                        # Finds the root of
    f(a, integrate(               # The integral of 
      f(x, x^a*exp(-x))           # The gamma function
        ,0 ,Inf                   # From 0 to Infinity
      )$value-z                   # Minus the input value, `z`
    ), c(0, z+1),                 # On the bound of 0 to z+1
    tol = 1e-323                  # With a specified tolerance
  )$root                          # And outputs the root
)                                 # End function

オンラインでお試しください!


0

Javascript(ループを使用せずに!)

これを行うために、私はスターリング因子近似の逆のよく知られた数値近似を使用しました(そして、この..咳..咳.. 他の誰かのコードからインスピレーションを得ました...)

function f(n){
    if(n==1) return 1;
    else if(n==2) return 2;
    else if(n==6) return 3;
    else if(n==24) return 4;
    else{
        return Math.round((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))/Math.log((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))))/Math.log((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))/Math.log((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))))))
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.