Pozitif bir sayının faktöriyelini nasıl bulurum?


18

Meydan okuma:

Pozitif bir sayı girip faktöriyelini döndüren bir program veya fonksiyon yazın .

Not: Bu bir sorusudur. Lütfen soruyu ve / veya cevapları ciddiye almayın. Daha fazla bilgi burada . Her sorusu aynı zamanda sorusudur, bu yüzden en yüksek oyu alan cevap kazanır.



4
-1, üzgünüm, çünkü bu kod trolling soruları büyük bir sel alıyoruz ve bu gerçekten onlara yeni bir şey
eklemiyor


Kod trollemesi, resmi duruşa göre kaldırılma sürecindedir . Bu soru, birçoğu son derece yüksek oy alan birçok cevabı olan adil bir oy sayısına sahiptir. Ankette % 50'nin biraz üzerinde "silme" oyu aldı , ancak çok fazla cevap ve oy alması benzersizdir, bu yüzden tarihsel önem için kilitliyorum.
Kapı tokmağı

Yanıtlar:


46

Bu, Stirling'in yaklaşımı ile çözebileceğimiz çok basit bir sayısal hesaplama problemidir :

Stirling'in yaklaştırma formülü

Gördüğünüz gibi, bu formül yaklaşık bir yola ihtiyacımız olacak bir kare köke sahiptir. Bunun için "Babil yöntemini" seçeceğiz çünkü tartışmasız en basit yöntem :

Babil yöntemi

Kare kökü bu şekilde hesaplamanın özyinelemenin iyi bir örneği olduğunu unutmayın.

Hepsini bir Python programında bir araya getirmek, sorununuza aşağıdaki çözümü sunar:

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)

Basit bir değişiklikle yukarıdaki program faktöriyelerin düzgün bir tablosunu çıkarabilir:

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

Bu yöntem çoğu uygulama için yeterince doğru olmalıdır.


16
+1 Bu yöntemin basitliği ve doğruluğu, onu açık bir kazanan yapar
Joe the Person

44

C #

Üzgünüm, ama özyinelemeli işlevden nefret ediyorum.

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

1
Teknik olarak, özetten memnun kaldınız! ;) Kısa süreli istismar için +1
WallyWest

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
Denedim - çok verimli. Bir sonraki sürümle birlikte gönderilecek. :)
Johannes

"Büyülü sayılar sendromunun" yanı sıra, n <13 olduğu sürece bu çok iyi bir uygulama olabilir. "Durum 4: dönüş 4 * 3 * 2;" ve eski özyinelemeli sınıftan çok daha hızlı, iyi bir sınıfınız olurdu.
Fabinout

6
@Fabinout, uygulama n> = 13 için bile doğrudur. 13!> Integer.MAX_VALUE.
emory

21

piton

Tabii ki herhangi bir sorunu çözmenin en iyi yolu düzenli ifadeler kullanmaktır:

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
Tabii ki :)
Pierre Arlaud

15

Haskell

Kısa kod etkili bir koddur, bu yüzden bunu deneyin.

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

Neden trolling yapıyor:

Bunu yazan herhangi bir kodlayıcıya gülerdim ... Verimsizlik güzel. Muhtemelen faktöriyel bir fonksiyon yazamayan herhangi bir Haskell programcısı için muhtemelen anlaşılmaz.

Düzenleme: Bunu bir süre önce yayınladım, ancak gelecekteki insanlar ve Haskell'i okuyamayan insanlar için açıklığa kavuşacağımı düşündüm.

Buradaki kod, 1'den n'ye kadar olan sayıların listesini alır, bu listenin tüm permütasyonlarının listesini oluşturur ve bu listenin uzunluğunu döndürür. Makinemde 13 için yaklaşık 20 dakika sürüyor !. Ve sonra 14 saat dört saat sürmeli! ve sonra 15 için iki buçuk gün !. Bunun dışında bir noktada hafızanız bitiyor.

Edit 2: Aslında Haskell olmasından dolayı muhtemelen hafızanız bitmeyecektir (aşağıdaki açıklamaya bakınız). Listeyi değerlendirmeye ve bir şekilde hafızada tutmaya zorlayabilirsiniz, ancak Haskell'i tam olarak nasıl yapılacağını bilmek için optimize etme (ve optimize etmeme) hakkında yeterince bilgim yok.


İğrenç ve yine de çok zarif, aynı anda.
PLL

1
Bellek sorunundan emin misiniz? Herhangi bir noktada, hafızada tutmanız gerekir: - liste [1..n]. - Belirli bir permütasyon, permütasyonların [1..n]geri kalanı için bir thunk'a kabul edilir (polinom içinde n). - lengthFonksiyon için bir akümülatör .
John Dvorak

Adil nokta, muhtemelen aslında değil. Gerçekten fazla düşünmemiştim. En alta bir yorum ekleyeceğim.
Mart'ta

10

C #

Bu bir matematik problemi olduğundan, bu hesaplamayı yapmak için matematik problemlerini çözmek için özel olarak tasarlanmış bir uygulamayı kullanmak mantıklıdır ...

Aşama 1:

MATLAB'ı yükleyin. Bir deneme işe yarayacağını düşünüyorum, ancak bu süper karmaşık sorunun uygulamanın tam sürümünü satın almayı hak edecek kadar önemli olması muhtemeldir.

Adım 2:

MATLAB COM bileşenini uygulamanıza ekleyin.

Aşama 3:

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

Öğrenciler için Matlab 100 $ 'dan başlıyor. Profesyonel sürümler veya site lisansları binlercesine girebilir.
Moshe Katz

4
Moshe Katz - haklı çünkü faktöriyeller.
Mike H.

9

C #

Faktörler, bir seferde sindirimi zor olabilecek daha yüksek bir matematik işlemidir. Bunun gibi programlama problemlerinde en iyi çözüm, büyük bir görevi daha küçük görevlere bölmektir.

Şimdi, n! 1 * 2 * ... * n olarak tanımlanır, yani özünde tekrarlanan çarpma ve çarpma tekrarlanan toplamadan başka bir şey değildir. Bunu akılda tutarak, aşağıdakiler bu sorunu çözer:

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

Tüm bunları bir CPU veya çekirdek üzerinden gönderen bir darboğazınız var, ki bu benim cevabımda çözmüş olabileceğimi düşünüyorum :-)
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;
}

Troller:

  • Bunu yinelemeli veya yinelemeli olarak yapma noktasını tamamen özleyen% 100 doğru hesaplama faktöriyeli.
  • Neden çalıştığı hakkında hiçbir fikriniz yok ve başka bir şey yapmak için genelleştiremediniz.
  • Tamsayı matematikle hesaplamaktan daha maliyetli.
  • z = n - 1 + 1Neler olduğunu biliyorsanız, en belirgin "suboptimal" kodu ( ) aslında kendi kendini belgelendirir.
  • Ekstra trolleme p[]için seri katsayıların özyinelemeli hesaplamasını kullanarak hesaplamalıyım!

( Lanczos'un gama fonksiyonuna yaklaşımıdır )


Burada bir anlamı - 1 + 1var mı? Derleyicim bunu optimize ediyor (bunun gibi kodları optimize etmenin tehlikeli olabileceği kayan nokta numarası değil), bu yüzden gereksiz görünüyor.
Konrad Borowski

4
@xfix: double z = n - 1gama fonksiyonunun yaklaşık bir parçasıdır. + 1Bu ilişkiden olan gamma(n + 1) = n!tam sayılar için n.
Ben Jackson

9

Hepimiz biliyoruz ki, çarpımı hesaplamanın en etkili yolu logaritma kullanmaktır. Sonuçta, insanlar neden yüzlerce yıldır logaritma masalarını kullansınlar?

Kimlikten a*b=e^(log(a)+log(b))şu Python kodunu oluşturuyoruz:

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)

Bu gelen numaralarının bir listesini oluşturur 1için x( +1her logaritmasını hesaplar Python berbat çünkü tabi) sayıları toplar, toplamı gücüne e yükseltir ve nihayet (Python berbat çünkü) en yakın tam sayıya değerini yuvarlar . Python'un faktöriyelleri hesaplamak için yerleşik bir işlevi vardır, ancak sadece tamsayılar için çalışır, bu nedenle büyük sayılar üretemez (çünkü Python berbat). Bu nedenle yukarıdaki fonksiyona ihtiyaç vardır.

Btw, öğrenciler için genel bir ipucu, eğer bir şey beklendiği gibi çalışmazsa, muhtemelen dil berbat olduğu içindir.


Orada açıklama için ekstra oy verebilir keşke, ama Python berbat
Mark K Cowan

1
Ben "fac you" güldüm
Number9

8

Ne yazık ki, Javascript faktöriyel hesaplamak için yerleşik bir yoldan yoksundur. Ancak, yine de değeri belirlemek için kombinatorikteki anlamını kullanabilirsiniz:

Bir n sayısının faktöriyeli, o büyüklükteki bir listenin permütasyon sayısıdır.

Böylece, n basamaklı sayının her listesini oluşturabilir, bir permütasyon olup olmadığını kontrol edebilir ve eğer öyleyse bir sayacı artırabiliriz:

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


Troller:

  • Macar notasyonu, yılan_kuvası ve gereksiz işaretler. Bu ne kadar kötü?
  • Bu sözleşmenin şu anki kullanımıyla uyumlu olmayan atlama etiketleri için kendi kuralımı icat ettim.
  • Olası her değişken kazara küreseldir.
  • Çözüm O(n)değil O(n!), değilO(n^n) . Bu sadece burada kalifiye olmak için yeterli olurdu.
  • Bir sayıyı artırmak ve daha sonra base-n olarak dönüştürmek, bir dizi listesi oluşturmak için kötü bir yoldur. Yinelenmek istesek bile. N> 13 için gizemli bir şekilde kırılma tek sebep değil.
  • Elbette kullanabilirdik number.toString(base), ama bu 36'nın üzerindeki bazlar için işe yaramıyor. Evet, 36'yı biliyorum! Bir olan çok ama yine de ...
  • Javascript'in modül operatörü olduğunu söylemiş miydim? VeyaMath.pow ? Hayır? Oh iyi.
  • ++For-loop'ların dışında kullanmayı reddetmek , onu daha gizemli hale getirir. Ayrıca, ==kötü.
  • Derin iç içe geçmiş braceless döngü yapıları. Ayrıca, AND yerine iç içe koşullu koşullar. Ayrıca, iç halkanın üzerindeki son döngü sona erdirilerek dış durumdan kaçınılabilirdi $i.
  • Fonksiyonlar new Array, document.write(arkadaşları ile) vealert (yerine bir istem veya bir giriş etiketin) işlevi seçimi günahların tam bir trifecta oluştururlar. Sonuçta giriş neden dinamik olarak ekleniyor?
  • Satır içi olay işleyicileri. Ve derin borular hata ayıklamak için cehennemdir.
  • Alıntılanmamış özellikler eğlencelidir ve etrafındaki boşluklar = okunmasını daha da zorlaştırır.
  • Noktalı virgüllerden nefret ettiğimi söylemiş miydim?

8

Ruby ve WolframAlfa

Bu çözüm faktöriyeli hesaplamak için WolframAlpha REST API'sini kullanır, çözümü getirmek için RestClient ve ayrıştırmak için Nokogiri kullanılır. Herhangi bir tekerleği yeniden icat etmez ve sonucu mümkün olan en modern şekilde elde etmek için iyi test edilmiş ve popüler teknolojiler kullanır.

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 işlevsel bir programlama dilidir, bu daha hızlı olduğu için her şey için işlevleri kullanmanız gerektiği anlamına gelir.

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
Açıklayabilir misin?
Mhmd

7
1 bir işlev değildir. Kodunuz yavaştır.
Pierre Arlaud

4
@ArlaudPierre r = -~(function(){})kesinlikle bunu çözecektir.
nitro2k01

4
Bir iş makinesindeyim, bu dili gerçekten kurmak istemiyorum. Tarayıcımda çalışacak bir sürümü nerede bulabilirim?
joeytwiddle

3
Google'ı kullanmaktan biraz korkuyorum çünkü patronumun bir hesabı var ve iş yerinde golf oynadığımı bilmesini istemiyorum. Firefox için Javascript çalıştırabilecek bir uzantı arıyordum, ancak bir tane bulamıyorum. Bazı arkadaşlarım jsfiddle.net üzerinde Javascript çalıştırıyor ama bu biraz çalmak gibi başkasının elektrik kullanıyor. Annem böyle insanlarla takılmamam gerektiğini söyledi, ama onlar benim arkadaşlarım yani ne yapabilirim? Her neyse bazen ihtiyaç duyduğundan daha fazla krema alıyor. İpuçları için teşekkürler, Firefox'ta Ctrl-Shift-J veya K kullanıyorum. Yasal Uyarı: # comment-trolling
joeytwiddle

5

Java'da Bogo-Sort'u kullanma

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

Bu aslında çok yavaş çalışıyor ve daha yüksek rakamlar için doğru değil.


4

PERL

Faktöriyel bir sorun olabilir. Google'ın kullandığı gibi bir harita / azaltma tekniği, bir sürü işlemi kesip sonuçları toplayarak matematiği bölebilir. Bu, soğuk bir kış gecesi sisteminizdeki tüm göbekleri veya cpusları iyi bir şekilde kullanacaktır.

Çalıştırabildiğinizden emin olmak için f.perl ve chmod 755 olarak kaydedin. Patolojik Olarak Eklektik Çöp Listeni yüklediniz, değil mi?

#!/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);
    }
}

Troller:

  • çatal O (log2 (N)) süreçleri
  • kaç CPU veya çekirdeğe sahip olduğunuzu kontrol etmiyor
  • Her işlemde gerçekleşen birçok bigint / metin dönüşümünü gizler
  • For döngüsü genellikle bu koddan daha hızlıdır

TIL bu perl ARGV[0]aslında ilk argüman değil, senaryo!
ThinkChaos

@plg $ 0 komut dosyasının dosya adını içerebileceğine inanıyorum, ancak bu $ ARGV ile aynı değil [0]
Paul

Evet, ben de öyle okudum. Ben sadece perl'de bunun $ARGV[0]birçok bildiğim biraz orada olması nedeniyle olmadığını şaşırtıcı buldum
ThinkChaos

4

piton

Faktöriyeli bulmak için sadece bir O (n! * N ^ 2) algoritması. Temel çanta ele alındı. Taşma yok.

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'te kolay bir çözüm var. Bir Golfscript yorumlayıcısı kullanabilir ve şu kodu çalıştırabilirsiniz:

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

Kolay ha :) İyi şanslar!


2
GolfScript'i bilmiyorum, ama bu beni hayal kırıklığına uğratıyor ... Bu sitedeki diğer GolfScript örneklerine dayanarak, cevabın olmasını beklerdim!
Bay Lister

1
Bu olumsuzlama operatörüdür. 0 1 olur ve diğer her şey 0 olur.
Martijn Courteaux

3

Mathematica

factorial[n_] := Length[Permutations[Table[k, {k, 1, n}]]]

11'den büyük sayılar için işe yaramıyor ve faktöriyel [11] bilgisayarımı dondurdu.


3

Yakut

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

Hayal edebileceğim en yavaş tek astarlı. Hesaplanması bir i7 işlemcide 2 dakika sürer 6!.


2

Bu zor matematik problemleri için doğru yaklaşım bir DSL'dir. Bu yüzden bunu basit bir dil açısından modelleyeceğim

data DSL b a = Var x (b -> a)
             | Mult DSL DSL (b -> a)
             | Plus DSL DSL (b -> a)
             | Const Integer (b -> a) 

DSL'imizi güzel bir şekilde yazmak için, cebirsel functor tarafından oluşturulan ücretsiz bir monad olarak görmek yararlıdır

F X = X + F (DSL b (F X)) -- Informally define + to be the disjoint sum of two sets

Bunu Haskell'de şöyle yazabiliriz:

Free b a = Pure a
         | Free (DSL b (Free b a))

Önemsiz uygulanmasını türetmek için okuyucuya bırakacağım

join   :: Free b (Free b a) -> Free b a
return :: a -> Free b a
liftF  :: DSL b a -> Free b a

Şimdi bu DSL'de bir faktöriyel modelleme işlemi yapabiliriz

factorial :: Integer -> Free Integer Integer
factorial 0 = liftF $ Const 1 id
factorial n = do
  fact' <- factorial (n - 1)
  liftF $ Mult fact' n id

Şimdi bunu modelleyebildiğimize göre, sadece ücretsiz monadımız için gerçek bir yorumlama işlevi sağlamamız gerekiyor.

denote :: Free Integer Integer -> Integer
denote (Pure a) = a
denote (Free (Const 0 rest)) = denote $ rest 0
...

Ve diğer ifadeleri okuyucuya bırakacağım.

Okunabilirliği artırmak için bazen formun somut bir AST'sini sunmak yararlı olabilir

data AST = ConstE Integer
         | PlusE AST AST
         | MultE AST AST

ve sonra önemsiz bir yansımayı düzeltmek

reify :: Free b Integer -> AST

ve daha sonra AST'yi tekrar tekrar değerlendirmek kolaydır.


2

piton

Aşağıda, Python'daki tamsayılar için 32 bit (veya çok yeni bir sistemde 64 bit) sınırıyla sınırlı olmayan bir Python sürümü bulunmaktadır. Bu sınırlamanın üstesinden gelmek için, factorialrutin için giriş ve çıkış olarak bir dize kullanmalı ve çarpmayı gerçekleştirebilmek için dizeyi basamaklarına böleriz.

İşte kod: getDigitsişlev, rakamı içindeki bir sayıyı temsil eden bir dizeyi ayırır, böylece "1234" olur [ 4, 3, 2, 1 ](ters sıra sadece increaseve multiplyişlevlerini kolaylaştırır). increaseFonksiyonu böyle bir liste ve tek artışları onu alır. Adından da anlaşılacağı gibi, multiplyişlev çoğalır, örneğin 12 çarpı 3 36 olduğu için multiply([2, 1], [3])geri döner. [ 6, 3 ]Bu, kalem ve kağıtla bir şeyi çarptığınız gibi çalışır.

Son olarak, factorialfonksiyon bu faktöriyeli gerçek faktöriyeli hesaplamak için kullanır, örneğin çıktısı olarak factorial("9")verir "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")

notlar

Python'da bir tamsayının bir sınırı yoktur, bu yüzden bunu manuel olarak yapmak istiyorsanız,

fac = 1
for i in range(2,n+1): 
    fac *= i

Ayrıca çok kullanışlı bir math.factorial(n)fonksiyon var.

Bu çözüm, olması gerekenden çok daha karmaşıktır, ancak işe yarar ve aslında 32 veya 64 bit ile sınırlı olmanız durumunda faktöriyel nasıl hesaplayabileceğinizi gösterir. Kimse bunun bu basit (en azından Python'da) problem için bulduğunuz çözüm olduğuna inanmayacak olsa da, aslında bir şeyler öğrenebilirsiniz.


Python'da tamsayı sayısında sınır yoktur ... değil mi? Bunu daha iyi açıklamanız gerekebilir.
Aralık'ta Riking

@Riking Evet, python'da tamsayılar için sınır yoktur. Daha anlaşılır olması için birkaç not ekledim.
brm

2

piton

En makul çözüm, verilen sayının faktöriyeli olanı bulana kadar tüm sayıları kontrol etmektir.

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'de en zarif özyinelemeli çözüm

Her biri faktöriyellere en zarif çözümlerin özyinelendiğini bilir.

Çarpınım:

0! = 1
1! = 1
n! = n * (n - 1)!

Ancak çarpma, yinelemeli olarak ardışık eklemeler olarak da tanımlanabilir.

Çarpma işlemi:

n * 0 = 0
n * 1 = n
n * m = n + n * (m - 1)

Ve art arda artışlar olarak ekleme de yapabilirsiniz.

İlave:

n + 0 = n
n + 1 = (n + 1)
n + m = (n + 1) + (m - 1)

İçinde C, ilkelleri kullanabilir ++xve --xidare edebiliriz (x + 1)ve (x - 1)sırasıyla, her şeyi tanımladık.

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

Hadi deneyelim:

$ ./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

Mükemmel, her ne kadar 8! bir sebepten dolayı uzun zaman aldı. Oh, en zarif çözümler her zaman en hızlı değil. Devam edelim:

$ ./factorial 9

Hmm, geri döndüğünde sana haber vereceğim ...


2

piton

@ Matt_Sieker'in cevabının da belirttiği gibi, faktöriyeller de eklenebilir - neden, görevlerin ayrılması programlamanın özüdür. Ancak, bunu 1'e ekleyebiliriz!

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)

Bu kod bir SO Hatası garanti düşünüyorum , çünkü

  1. Özyineleme- ısıtır

  2. Her katman çarpılacak çağrılar oluşturur

  3. addnumbers çağrıları üreten

  4. hangi addby1 çağrıları üretir!

Çok fazla fonksiyon, değil mi?



1

TI-Basic 84

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

Gerçekten çalışıyor :)


1

JavaScript

Açıkçası bir programcının işi olabildiğince az iş yapmak ve mümkün olduğunca çok kütüphane kullanmaktır. Bu nedenle, jQuery ve math.js dosyasını içe aktarmak istiyoruz . Şimdi, görev bu kadar basit:

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

1

piton

Standart özyinelemeli faktöriyel uygulamada sadece küçük bir değişiklikle n> 10 için dayanılmaz derecede yavaş hale gelir.

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

darbe

#! /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

Bunu Monte Carlo Yöntemi ile yapmaya çalışalım . Hepimiz biliyoruz ki, iki rastgele n- çarpımı eşit olma olasılığı tam olarak 1 / n! . Bu nedenle, c isabet alana kadar kaç testin gerekli olduğunu kontrol edebiliriz (hadi bu sayı b olarak adlandıralım ) . O zaman, n! ~ b / c .

Adaçayı, Python'da da çalışmalı

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

darbe

Faktörler bash'ın iyi bilinen komut satırı araçlarıyla kolayca belirlenir.

read -p "Enter number: " $n
seq 1 $n | xargs echo | tr ' ' '*' | bc

@Aaron Davies'in yorumlarda belirttiği gibi, bu çok daha düzenli görünüyor ve hepimiz güzel ve düzenli bir program istiyoruz, değil mi?

read -p "Enter number: " $n
seq 1 $n | paste -sd\* | bc

1
çok abartılı pastekomutu öneriyorum :seq 1 $n | paste -sd\* | bc
Aaron Davies

2
@AaronDavies pastenormal İngilizce bir kelime gibi görünüyor ve hatırlanması kolay. Bunu gerçekten istiyor muyuz? ; o)
jippie
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.