Faktoringin tersini hesaplayın


30

Girdi olarak 1'den büyük olan herhangi bir gerçek sayı alacak ve pozitif ters faktörlemesini çıkartacak en kısa kodu yazın. Başka bir deyişle, "Bu sayıya hangi sayı faktörü eşittir?" Sorusuna cevap verir. Faktöryal tanımını burada açıklanan herhangi bir gerçek sayıya genişletmek için Gama işlevini kullanın .

Örneğin:

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

çünkü 3! = 6ve3.390077654! = 10

kurallar

  • Faktöriyel fonksiyonlarda veya gama fonksiyonlarında veya bu fonksiyonlara dayanan fonksiyonlarda kullanılması yasaktır.
  • Program, herhangi bir kesinlikte hesaplayabilmesi için teorik yeteneği ile 5 ondalık basamağa kadar hesap verebilmelidir (Keyfi bir hassasiyet elde etmek için keyfi büyük veya küçük yapılabilir).
  • Herhangi bir dile izin verilir, karakterlerde en kısa kod kazanır.

Burada çalışan bir örnek yaptım . Bir göz atın.


2
Bu, özellikle sıfır ve negatif girdileri kapsayacak şekilde bazı test durumları kullanabilir.
Peter Taylor

Girişin 1'den büyük olması gerektiğini düzenledim, çünkü aksi halde muliple cevaplar olabilir.
Jens,

1
Çıktının 1'den büyük olması şartını da eklemediğiniz sürece, yine de birden fazla cevap olabilir.
Peter Taylor

Çalışma örneğiniz 24 girdiğinde 3.99999 veriyor. Öyleyse böyle bir çözüm kabul edilebilir mi?
rubik

evet, çünkü bu 4 ila 5 ondalık basamağı doğru olarak görülebilir
Jens Render

Yanıtlar:


13

Javascript (116)

Burada kara büyüler! Birkaç milisaniyede bir sonuç verir .
Sadece ilköğretim matematik fonksiyonları kullanılır: ln, pow,exponential

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)

Çok kötü LaTeX codegolf desteklenmez ama temelde, şifreli bir newton çözücü için f(y)=gamma(y)-n=0ve x=y-1(çünkü x!olduğunu gamma(x+1)) ve yaklaşımları gamma ve digamma işlevleri için.

Gamma yaklaşımı Stirling yaklaşımıdır
Digamma yaklaşımı kullanımı Euler Maclaurin formülü
Diggamma fonksiyonu, gamma fonksiyonunun bölünmüş gamma fonksiyonunun türevidir:f'(y)=gamma(y)*digamma(y)

Ungolfed:

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

Test durumları:

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

Bunun taşıyamazsınız Çok güzel cevabı gerektirdiği hassasiyet uymayan ve sadece 706 daha az sayılar için çalışıyor
Jens oluşturur

@JensRenders, newton çözücüsünün bazı yinelemelerini ekledim, ilk tahmini değiştirdim ve gama fonksiyonu için daha iyi bir yaklaşım. Bu şimdi kurallara uymalı. Eğer şimdi sorun yok ise :)
Michael M.

Evet, şimdi mükemmel, ben oy kullandım :)
Jens Renders

1
1 karakter kaydedebilirsiniz: n=prompt(M=Math)
Florent

Kodunuzu $ 10 ^ {10 ^ 6} $ gibi çok sayıda çalıştırmayı deneyin ve bir tamsayı sonucu aldığınızdan emin olun
David G. Stork

13

Mathematica - 74 54 49

Uygun yolu olacak

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

Testi yeni bırakırsak ?NumberQyine de işe yarayacak, ancak sembolik entegrasyona geçersek kaybolacak bazı kötü uyarılar atacak Integrate, ancak bu yasadışı olacaktır (sanırım) çünkü işlev otomatik olarak Gammaişleve dönüştürülür . Ayrıca dış işlevden de bu şekilde kurtulabiliriz.

neyse

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

Düzgün giriş ile kontrol etmek için, sadece işlev tanımı (MatLab'ın kazanmasına izin vermeyin)

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

Yerleşik faktoringe izin verildiyse

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

Yukarıdakiler bir tamsayı vermez (bu, gerçek bir faktör işlevinin argümanıdır). Aşağıdakileri yapar:

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

Ahh bütün bu yerleşik işlevler! Benzer bir durum dışında bunun dövülebilir olduğunu sanmıyorum.
rubik

4
Mathematica, matematik işleri için haksızlık! : D
Michael M.

1
MATHematica isminden
Dadan

Is NumberQdesen testi gerekli? Veya parens E^(-t)? Açmak NIntegrateiçin hile Integratemi? Muhtemelen ... :)
orion

Gerçek bir mücadeleye dönüşüyor;)
mmumboss

6

ised: 72 46 karakter

Bu neredeyse mükemmel bir uyum ... tam olarak matematik golf için kastedilen görünen bir "dil" var: ised . Onun karışık sözdizimi çok kısa bir kod (adlandırılmış değişken yok, sadece tamsayı bellek yuvaları ve çok yönlü çok yönlü tek karakter operatörleri) yapar. Bir integral kullanarak gama fonksiyonunu tanımlayarak 80 görünüşte rastgele karakterler elde ettim.

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

Burada, $ 4 bellek yuvası faktörsal bir işlevdir, 6 $ bellek bölme işlevini ve $ 2 bellek yuvasının giriş olarak ayarlanması beklenir (bu kodu girmeden önce verilir). 0 $ ve 1 $ arasındaki slotlar bisection sınırlarıdır. Çağrı örneği (yukarıdaki kodun dosyada olduğunu varsayarak inversefactorial.ised)

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

Tabii ki, yerleşik yerleşik kullanabilirsiniz! operatör, bu durumda en fazla 45 karakter

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

Dikkatli, operatör önceliği bazen gariptir.

Düzenleme: fonksiyonları kaydetmek yerine satır içi yapmayı hatırladım. 72 karakterli Mathematica'yı bitirin!

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

Ve kullanma! Yerleşik 41 olsun.


Bir yıl gecikmeli güncelleme:

Bunun çok verimsiz olduğunu anladım. 60 karaktere kadar golf oynadı:

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

Utf-8 kullanılırsa (Mathematica da yapar), 57'ye ulaşırız:

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

Biraz farklı bir yeniden yazma işlemi 46'ya kadar azaltabilir (veya eğer yerleşik kullanıyorsanız 27):

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

Son iki karakter, cevabın iki kez yazdırılmasıyla sorununuzu çözmeniz durumunda kaldırılabilir.


Bunu yenen birini görürsem
şaşırırdım

@JensRenders: Sadece yaptım;)
mmumboss

Doğruluk hakkındaki tartışmayı açıklığa kavuşturmak için: .1 (entegrasyon adımı) ve 99 (entegrasyon sınırı) ile ayarlanır. Bisection makine hassasiyetine gider. Yukarıdaki rakamları (99!) Girmek istemediğiniz sürece, ikiye bölme sınırı @ 1,99, 99'da tutulabilir.
orion

@ mmumboss yine oldu seni :)
orion

5

MATLAB 54 47

Doğru zorlukları seçersem MATLAB golf oynamak için gerçekten çok güzel :). Benim kodumda, u'nun kullanıcı girişi olduğu ve (çözülecek değişkenin x olduğu) (ux!) = 0 denkleminin çözümünü buluyorum. Bunun anlamı, u = 6, x = 3 vb.

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

Doğruluk, 99'a ayarlanan integralin üst sınırını değiştirerek değiştirilebilir. Bunun düşürülmesi çıktının doğruluğunu aşağıdaki gibi değiştirecektir. Örneğin 10 giriş için:

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

vb.


Kurallarda gerekli olduğu için doğruluk seçeneğini belirlemelisiniz! "Keyfi bir hassasiyet elde etmek için keyfi büyük veya küçük yapılabilecek bir sayı içermelidir"
Jens Renders

İsed ve Mathematica çözümlerinde de görmüyorum? Ama içine bakacağım ..
mmumboss

1
İsed versiyonunda 99 sayısını görüyorum ve matematiksel versiyon yine de dövülmüş
Jens Renders

Koddaki pozisyon göz önüne alındığında, bu muhtemelen integral için üst sınırdır. Benim kodumda bu inf. Bu yüzden evet, eğer bu enfeksiyonu 99 olarak değiştirirsem cevabım daha az kesinleşir, bu sayede bu sayı kesinliği etkiler ve bu yüzden kuralları yerine getiririm. 99'a değiştirirsem bile bir char;;
mmumboss

Fakat inf'i 99'a değiştirdikten sonra gereken hassasiyeti sağlıyor mu?
rubik

3

Python - 199 karakter

Tamam, çok fazla yığın alanına ve zamana ihtiyacınız olacak, ama hey, oraya gelecek!

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)

İşte daha fazla özyineleme ile başka bir yaklaşım.

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)

Bunların her ikisi de ile test edilebilir >>>f(10,1) , özyineleme sınırını 10000 civarında ayarlamanız koşuluyla . Birden fazla ondalık doğruluk yeri, herhangi bir gerçekçi özyineleme sınırına uymayabilir.

Yorum ve birkaç değişiklik yapma, 199 karaktere kadar.

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
Bu bir code-golfsorudur, bu nedenle çözümünüzün uzunluğunu belirten en kısa cevabı sağlamanız gerekir.
18'de

Güzel bir yöntem, ancak sorun şu ki, cevabı bulamayacağınızı garanti edemezsiniz. Ayrıca, karakter kullanımını en aza indirmeyi deneyebilirsiniz.
Jens,

1
Python'un rastgele () yöntemi, Python'un yüzdüğü alanda yürüdüğünü düşündüğüm bir Mersenne Twister kullanıyor, bu nedenle tolerans dahilinde bir cevap varsa daima sona ermelidir.
intx13

Birini tekrar etmeden önce her bir kayan değeri döndürdüğünü mü kastediyorsunuz? Yığın taşmasının üstesinden gelebilecek olursanız, bu koddan daha geçerliyse geçerli olur
Jens Renders

2
Kod yetenekli, sadece sen ve ben bunu tamamlamak için zamana veya bilgisayar kaynaklarına sahip olmayabiliriz;)
intx13

3

Python 2.7 - 215 189 karakter

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)

Kullanımı:

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

Hassasiyeti değiştirmek 1e-5için : daha büyük hassasiyet için daha küçük bir sayıya, daha kötü hassasiyet için daha büyük bir sayıya değiştirin. Daha iyi hassasiyet için muhtemelen daha iyi bir değer vermek istersiniz e.

Bu sadece faktoring işlevini uygular fve ardından girişin tersinin en doğru değerine girmek için ikili bir arama yapar. Cevabın 99'a eşit veya daha küçük olduğunu varsayar (elbette 365 cevabı için işe yaramaz, bir matematik taşması hatası alıyorum). Çok makul yer ve zaman kullanımı, daima sona ermektedir.

Alternatif olarak, 50 karakteri tıraş if abs(n-f(x))<=10**-5: print x;breaketmek print xiçin ile değiştirin . Sonsuza dek döngüde olacak ve size daha doğru bir tahmin verecek. Ancak bu kurallara uygun olup olmadığından emin değil.


Karakterleri saymak için o siteyi bilmiyordum. Ben her zaman kullanırım cat file | wc -c.
rubik

@ rubik: güzel, bunu kullanmayı düşünmedim. ikisi de
eşleşiyor

2

dg - 131 133 bayt

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 bayt kodunu ürettiğinden, bunun Python için de geçerli olması gerekir, ancak oh ... Bazı örnekler:

$ 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

EDIT: İki bayt eklendi, çünkü onun da floatları kabul etmesi gerektiğini hatırlamadım!


Mine verir 42.8006566063, bu yüzden 5 hassasiyet içinde eşleşir!
Claudiu

Bu harika! Üst sınırın nerede olduğunu bilmiyorum ama bir yerlerden kırılmalı. İçin 1e100o verir: 69.95780520000001için 1e150o verir 96.10586423000002, için oysa 1e200o havaya uçuruyor. Ama gerçekten bu sonuçların güvenilir olup olmadığını bilmiyorum ...
rubik

1

R , 92 bayt

gGirdiyi alan zve o sayının ters faktörünü çıkaran bir işlev

Neredeyse kesinlikle bundan daha fazla golf oynamak mümkün, o yüzden geliştirebileceğim bir şey görürseniz, lütfen bana bildirin.

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)

Çevrimiçi deneyin!

Ungolfed ve Yorumlandı

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

Çevrimiçi deneyin!


0

Javascript (döngüler kullanmadan!)

Bunu yapmak için , Stirling Factorial yaklaşımının tersinin bilinen bir sayısal yaklaşımını kullandım (ve ayrıca bu ..cough .. öksürük .. başka birinin kodundan da ilham aldım ...)

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)))))))))
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.