Wie finde ich die Fakultät einer positiven Zahl?


18

Die Herausforderung:

Schreiben Sie ein Programm oder eine Funktion, die eine positive Zahl eingibt und deren Fakultät zurückgibt .

Hinweis: Dies ist eine Frage. Bitte nehmen Sie die Frage und / oder die Antworten nicht ernst. Mehr Infos hier . Jede Frage ist auch eine Frage des , daher gewinnt die Antwort mit der höchsten Stimmenzahl.



4
-1, sorry, weil wir eine riesige Flut dieser Code-Trolling-Fragen bekommen und dies ihnen nicht wirklich etwas Neues hinzufügt
Doorknob


Der offizielle Standpunkt besagt, dass Code-Trolling derzeit entfernt wird . Diese Frage hat eine angemessene Anzahl von Stimmen mit vielen Antworten, von denen viele extrem hoch bewertet sind. Es hat etwas mehr als 50% "Lösch" -Stimmen bei der Umfrage erhalten , aber es ist insofern einzigartig, als es so viele Antworten und Stimmen erhalten hat, dass ich es für die historische Bedeutung sperre.
Türklinke

Antworten:


46

Dies ist ein sehr einfaches numerisches Rechenproblem, das wir mit Stirlings Näherung lösen können :

Stirlings Näherungsformel

Wie Sie sehen, enthält diese Formel eine Quadratwurzel, die wir auch approximieren müssen. Wir werden dafür die sogenannte "babylonische Methode" wählen , weil es wohl die einfachste ist:

Babylonische Methode

Beachten Sie, dass die Berechnung der Quadratwurzel auf diese Weise ein gutes Beispiel für die Rekursion ist.

Wenn Sie alles in einem Python-Programm zusammenfassen, erhalten Sie die folgende Lösung für Ihr Problem:

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)

Mit einer einfachen Modifikation kann das obige Programm eine übersichtliche Tabelle mit Fakultäten ausgeben:

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

Diese Methode sollte für die meisten Anwendungen ausreichend genau sein.


16
+1 Die Einfachheit und Genauigkeit dieser Methode macht es zu einem klaren Gewinner
Joe the Person

44

C #

Sorry, aber ich hasse rekursive Funktion.

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

1
Technisch haben Sie den Auftrag erfüllt! ;) +1 für kurzzeitigen Missbrauch
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
Ich habe es versucht - sehr effizient. Wird mit der nächsten Version ausgeliefert. :)
Johannes

Neben dem "magischen Zahlensyndrom" könnte dies tatsächlich eine gute Implementierung sein, solange n <13 ist, viel weniger Stapel. Schreibe es "case 4: return 4 * 3 * 2;" und du hättest eine anständige Klasse, viel schneller als die alte rekursive.
Fabinout

6
@Fabinout, die Implementierung ist auch für n> = 13 korrekt. 13!> Integer.MAX_VALUE.
Emory

21

Python

Der beste Weg, um ein Problem zu lösen, ist natürlich die Verwendung regulärer Ausdrücke:

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
Natürlich in der Tat :)
Pierre Arlaud

15

Haskell

Funktionscode ist effizienter Code. Versuchen Sie dies.

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

Warum trollt es:

Ich würde jeden Coder auslachen, der das geschrieben hat ... Die Ineffizienz ist wunderschön. Wahrscheinlich auch unverständlich für jeden Haskell-Programmierer, der keine Fakultätsfunktion schreiben kann.

Bearbeiten: Ich habe dies vor einer Weile gepostet, aber ich dachte, ich würde für zukünftige Menschen und Menschen, die Haskell nicht lesen können, klären.

Der Code nimmt hier die Liste der Zahlen 1 bis n, erstellt die Liste aller Permutationen dieser Liste und gibt die Länge dieser Liste zurück. Auf meinem Computer dauert es ungefähr 20 Minuten für 13 !. Und dann sollte es für 14 vier Stunden dauern! und dann zweieinhalb Tage für 15 !. Abgesehen davon, dass Ihnen irgendwann der Speicher ausgeht.

Bearbeiten 2: Eigentlich werden Sie wahrscheinlich nicht über genügend Arbeitsspeicher verfügen, da dies Haskell ist (siehe den Kommentar unten). Sie können ihn möglicherweise zwingen, die Liste auszuwerten und sie irgendwie im Speicher zu halten, aber ich weiß nicht genug über das Optimieren (und Nichtoptimieren) von Haskell, um genau zu wissen, wie das geht.


Abscheulich und doch so elegant zugleich.
PLL

1
Sind Sie sich über das Speicherproblem sicher? Zu jedem Zeitpunkt müssen Sie Folgendes im Gedächtnis behalten: - die Liste [1..n]. - Eine bestimmte Permutation von [1..n], die für den Rest der Permutationen einem Thunk zugeordnet ist (Polynom in n). - Ein Akku für die lengthFunktion.
John Dvorak

Richtiger Punkt, wahrscheinlich nicht wirklich. Ich habe nicht wirklich viel darüber nachgedacht. Ich werde unten einen Kommentar hinzufügen.
jgon

10

C #

Da es sich um ein mathematisches Problem handelt, ist es sinnvoll, eine Anwendung zu verwenden, die speziell für die Lösung mathematischer Probleme entwickelt wurde, um diese Berechnung durchzuführen ...

Schritt 1:

Installieren Sie MATLAB. Ich denke, eine Testversion wird funktionieren, aber dieses superkomplizierte Problem ist wahrscheinlich wichtig genug, um die Vollversion der Anwendung zu erwerben.

Schritt 2:

Binden Sie die MATLAB COM-Komponente in Ihre Anwendung ein.

Schritt 3:

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

Matlab für Studenten beginnt bei 100 US-Dollar. Professionelle Versionen oder Site-Lizenzen können in die Tausende gehen.
Moshe Katz

4
Moshe Katz - gerechtfertigt wegen Fakultäten.
Mike H.

9

C #

Factorials sind eine übergeordnete mathematische Operation, bei der es schwierig sein kann, alles auf einmal zu verdauen. Die beste Lösung für solche Programmierprobleme besteht darin, eine große Aufgabe in kleinere Aufgaben zu unterteilen.

Nun, n! ist definiert als 1 * 2 * ... * n, also im Wesentlichen wiederholte Multiplikation, und Multiplikation ist nichts anderes als wiederholte Addition. In diesem Sinne löst das Folgende dieses Problem:

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

Sie haben einen Engpass, der das alles durch eine CPU oder einen Kern schickt, den ich wahrscheinlich in meiner Antwort gelöst habe :-)
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;
}

Trolle:

  • Eine zu 100% korrekte Methode zur Berechnung von Fakultäten, bei der entweder iterativ oder rekursiv keine Aussage getroffen wird.
  • Sie haben keine Ahnung, warum es funktioniert, und können es nicht verallgemeinern, um etwas anderes zu tun.
  • Kostspieliger als nur die Berechnung mit ganzzahliger Mathematik.
  • Der offensichtlichste "suboptimale" Code ( z = n - 1 + 1) dokumentiert sich selbst, wenn Sie wissen, was los ist.
  • Für zusätzliches Trolling sollte ich p[]eine rekursive Berechnung der Serienkoeffizienten verwenden!

(Es ist die Lanczos-Näherung der Gammafunktion )


Gibt es hier irgendeinen Punkt - 1 + 1? Mein Compiler optimiert es (es ist keine Fließkommazahl, bei der die Optimierung von Code wie diesem gefährlich sein könnte), sodass es nicht erforderlich zu sein scheint.
Konrad Borowski

4
@xfix: double z = n - 1ist Teil der Approximation der Gammafunktion. Das + 1ist aus der Beziehung, die gamma(n + 1) = n!für die ganze Zahl n.
Ben Jackson

9

Wir alle wissen vom College, dass die effizienteste Methode zur Berechnung einer Multiplikation die Verwendung von Logarithmen ist. Warum sonst würden die Leute Logarithmentabellen für Hunderte von Jahren benutzen?

Also von der Identität a*b=e^(log(a)+log(b)) bilden wir den folgenden Python-Code:

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)

Es erstellt eine Liste von Zahlen aus 1 bis erstellt x( +1wird benötigt, weil Python saugt), der Logarithmus der einzelnen berechnet, die Zahlen summiert, das e zur Potenz der Summe erhöht und schließlich den Wert auf die nächste Ganzzahl gerundet (weil Python saugt). . Python verfügt über eine integrierte Funktion zum Berechnen von Fakultäten, funktioniert jedoch nur für Ganzzahlen, sodass keine großen Zahlen erzeugt werden können (weil Python nervt). Aus diesem Grund wird die obige Funktion benötigt.

Übrigens, ein allgemeiner Tipp für Studenten ist, dass wenn etwas nicht wie erwartet funktioniert, es wahrscheinlich daran liegt, dass die Sprache nicht stimmt.


Ich wünschte, ich könnte dort ein paar zusätzliche Stimmen für die Beschreibung abgeben, aber Python ist scheiße
Mark K Cowan

1
Ich habe über "fac you" gelacht
Nummer 9

8

Leider fehlt Javascript eine eingebaute Möglichkeit, die Fakultät zu berechnen. Sie können seine Bedeutung jedoch in der Kombinatorik verwenden, um den Wert dennoch zu bestimmen:

Die Fakultät einer Zahl n ist die Anzahl der Permutationen einer Liste dieser Größe.

Wir können also jede Liste mit n-stelligen Zahlen generieren, prüfen, ob es sich um eine Permutation handelt, und in diesem Fall einen Zähler inkrementieren:

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


Trolle:

  • Schreibt ungarische Notation, snake_case und unnötige Siegel. Wie böse ist das denn?
  • Ich habe meine eigene Konvention für Sprungmarken erfunden, die mit der aktuellen Verwendung dieser Konvention nicht kompatibel ist.
  • Jede mögliche Variable ist versehentlich global.
  • Die Lösung ist nicht O(n), nicht O(n!), aber O(n^n). Dies allein hätte ausgereicht, um sich hier zu qualifizieren.
  • Das Inkrementieren einer Zahl und das anschließende Konvertieren als Basis-n ist eine schlechte Methode, um eine Liste von Sequenzen zu generieren. Auch wenn wir Duplikate wollten. Das mysteriöse Brechen für n> 13 ist nicht der einzige Grund.
  • Natürlich hätten wir es gebrauchen können number.toString(base), aber das funktioniert nicht für Basen über 36. Ja, ich weiß 36! ist viel , aber immer noch ...
  • Habe ich erwähnt, dass Javascript den Modul-Operator hat? OderMath.pow ? Nein? Naja.
  • Die Verweigerung der Verwendung ++außerhalb von for-Loops macht es noch mysteriöser. Auch ==ist schlecht.
  • Tief verschachtelte armbandlose Schleifenkonstrukte. Auch geschachtelte Bedingungen anstelle von AND. Außerdem hätte der äußere Zustand vermieden werden können, indem die innere Schleife bei beendet worden wäre $i.
  • Die Funktionen new Array, document.write(mit Freunden) und alert(statt einer Eingabeaufforderung oder ein Eingangsschild) eine vollständige trifecta der Funktion Wahl Sünden bilden. Warum wird die Eingabe doch dynamisch hinzugefügt?
  • Inline-Ereignishandler. Oh, und Deep Piping ist die Hölle zum Debuggen.
  • Attribute ohne Anführungszeichen machen Spaß und die Leerzeichen herum = noch schwerer zu lesen.
  • Habe ich schon erwähnt, dass ich Semikolons hasse?

8

Ruby und WolframAlpha

Diese Lösung verwendet die WolframAlpha-REST-API zur Berechnung der Fakultät, wobei RestClient zum Abrufen der Lösung und Nokogiri zum Parsen der Lösung verwendet wird. Es erfindet keine Räder neu und nutzt bewährte und beliebte Technologien, um das Ergebnis auf modernste Weise zu erzielen.

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 ist eine funktionale Programmiersprache, das heißt, Sie müssen Funktionen für alles verwenden, weil es schneller ist.

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
Können Sie erklären?
Mhmd

7
1 ist keine Funktion. Dein Code ist also langsam.
Pierre Arlaud

4
@ArlaudPierre r = -~(function(){})wird das sicher lösen.
Nitro2k01

4
Ich bin auf einer Arbeitsmaschine und möchte diese Sprache nicht wirklich installieren. Wo finde ich eine Version, die in meinem Browser ausgeführt wird?
Joeytwiddle

3
Ich habe ein bisschen Angst davor, Google zu verwenden, weil mein Chef ein Konto bei ihnen hat und ich möchte nicht, dass er weiß, dass ich auf der Arbeit Golf spiele. Ich habe nach einer Erweiterung für Firefox gesucht, die Javascript ausführen kann, aber ich kann anscheinend keine finden. Einige meiner Freunde betreiben Javascript auf jsfiddle.net, aber das verbraucht die Elektrizität eines anderen, was ein bisschen wie Stehlen ist. Meine Mutter sagte, ich solle nicht mit solchen Leuten rumhängen, aber sie sind meine Freunde. Was kann ich also tun? Auf jeden Fall nimmt sie manchmal mehr Milch, als sie braucht. Danke für die Tipps, ich benutze Ctrl-Shift-J oder K in Firefox. Haftungsausschluss: # comment-
trolling

5

Bogo-Sort in Java verwenden

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

Dies funktioniert eigentlich nur sehr langsam und ist bei höheren Zahlen nicht korrekt.


4

PERL

Factorial kann ein schweres Problem sein. Eine Map / Reduce-ähnliche Technik kann - genau wie Google - die Mathematik aufteilen, indem eine Reihe von Prozessen abgebrochen und die Ergebnisse gesammelt werden. Dadurch werden in einer kalten Winternacht all diese Kerne oder CPUs in Ihrem System optimal genutzt.

Speichern Sie als f.perl und chmod 755, um sicherzustellen, dass Sie es ausführen können. Sie haben den pathologisch vielseitigen Mülleimer installiert, nicht wahr?

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

Trolle:

  • gabelt O (log2 (N)) Prozesse
  • überprüft nicht, wie viele CPUs oder Kerne Sie haben
  • Versteckt viele Bigint / Text-Konvertierungen, die in jedem Prozess auftreten
  • Eine for-Schleife ist oft schneller als dieser Code

Bis dass in Perl ARGV[0]tatsächlich das erste Argument und nicht das Skript ist!
ThinkChaos

@plg Ich glaube, $ 0 könnte den Dateinamen des Skripts enthalten, aber das ist nicht dasselbe wie $ ARGV [0]
Paul

Ja, das habe ich gelesen. Ich fand es nur überraschend, dass es in Perl nicht so ist, $ARGV[0]weil die meisten Sprachen, die ich ein bisschen kenne, es dort haben
ThinkChaos

4

Python

Nur ein O (n! * N ^ 2) Algorithmus, um die Fakultät zu finden. Grundfall behandelt. Keine Überläufe.

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

Nun, es gibt eine einfache Lösung in Golfscript. Sie könnten einen Golfscript-Interpreter verwenden und diesen Code ausführen:

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

Einfach huh :) Viel Glück!


2
Ich kenne GolfScript nicht, aber dieses enttäuscht mich ... Aufgrund der anderen GolfScript-Beispiele auf dieser Site hätte ich erwartet, dass die Antwort!
Mr Lister

1
Das ist der Negationsoperator. 0 wird 1 und alles andere wird 0.
Martijn Courteaux

3

Mathematica

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

Es scheint nicht für Zahlen größer als 11 zu funktionieren, und Fakultät [11] hat meinen Computer eingefroren.


3

Rubin

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

Der langsamste Einzeiler, den ich mir vorstellen kann. Die Berechnung auf einem i7-Prozessor dauert 2 Minuten 6!.


2

Der richtige Ansatz für diese schwierigen mathematischen Probleme ist ein DSL. Also werde ich dies in einer einfachen Sprache modellieren

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

Um unser DSL gut zu schreiben, ist es hilfreich, es als freie Monade anzusehen, die vom algebraischen Funktor generiert wird

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

Wir könnten dies in Haskell als schreiben

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

Ich überlasse es dem Leser, die triviale Umsetzung von abzuleiten

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

Nun können wir eine Operation beschreiben, um eine Fakultät in dieser DSL zu modellieren

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

Nachdem wir dies modelliert haben, müssen wir lediglich eine tatsächliche Interpretationsfunktion für unsere freie Monade bereitstellen.

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

Den Rest der Bezeichnung überlasse ich dem Leser.

Um die Lesbarkeit zu verbessern, ist es manchmal hilfreich, einen konkreten AST des Formulars vorzulegen

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

und dann gleich eine triviale Überlegung

reify :: Free b Integer -> AST

und dann ist es einfach, den AST rekursiv auszuwerten.


2

Python

Nachfolgend finden Sie eine Python-Version der Lösung, die nicht auf das 32-Bit-Limit (oder 64-Bit-Limit auf einem neueren System) für Ganzzahlen in Python beschränkt ist. Um diese Einschränkung zu umgehen, werden wir eine Zeichenfolge als Eingabe und Ausgabe für die factorialRoutine verwenden und die Zeichenfolge intern in ihre Ziffern aufteilen, um die Multiplikation durchführen zu können.

Hier ist der Code: Die getDigitsFunktion teilt eine Zeichenfolge, die eine Zahl darstellt, in ihre Ziffern auf, sodass "1234" wird [ 4, 3, 2, 1 ](die umgekehrte Reihenfolge vereinfacht nur die Funktionen increaseund multiply). Die increaseFunktion nimmt eine solche Liste und erhöht sie um eins. Wie der Name schon sagt, multiplymultipliziert sich die Funktion, z. B. wird multiply([2, 1], [3])zurückgegeben, [ 6, 3 ]weil 12 mal 3 gleich 36 ist. Dies funktioniert genauso, als würden Sie etwas mit Stift und Papier multiplizieren.

Dann endlich, die factorialverwendet Funktion diese Hilfsfunktionen die tatsächlichen faktorielles zu berechnen, zum Beispiel factorial("9")gibt "362880"als Ausgabe.

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

Anmerkungen

In Python gibt es für eine Ganzzahl kein Limit. Wenn Sie dies also manuell tun möchten, können Sie dies einfach tun

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

Es gibt auch die sehr bequeme math.factorial(n)Funktion.

Diese Lösung ist offensichtlich weitaus komplexer als nötig, funktioniert jedoch und zeigt in der Tat, wie Sie die Fakultät berechnen können, wenn Sie auf 32 oder 64 Bit begrenzt sind. Obwohl niemand glauben wird, dass dies die Lösung für dieses einfache (zumindest in Python) Problem ist, können Sie tatsächlich etwas lernen.


In Python gibt es keine Begrenzung für Ganzzahlen ... richtig? Möglicherweise müssen Sie dies besser erklären.
Riking

@Riking Ja, in Python gibt es keine Begrenzung für ganze Zahlen. Ich habe ein paar Notizen hinzugefügt, um es klarer zu machen.
frühestens

2

Python

Die vernünftigste Lösung besteht eindeutig darin, alle Zahlen zu überprüfen, bis Sie diejenige finden, die die Fakultät der angegebenen Zahl ist.

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

Eine eleganteste rekursive Lösung in C

Jeder weiß, dass die elegantesten Lösungen für Fakultäten rekursiv sind.

Fakultät:

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

Die Multiplikation kann aber auch rekursiv als sukzessive Addition definiert werden.

Multiplikation:

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

Und so lassen sich auch nacheinander Inkrementierungen vornehmen.

Zusatz:

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

In C, können wir verwenden ++xund --xdie Grundelemente zu handhaben (x + 1)und (x - 1)jeweils, so dass wir alles definiert haben.

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

Probieren wir es aus:

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

Perfekt, obwohl 8! hat aus irgendeinem Grund lange gedauert. Na ja, die elegantesten Lösungen sind nicht immer die schnellsten. Lass uns weitermachen:

$ ./factorial 9

Hmm, ich werde dich wissen lassen, wenn es zurückkommt ...


2

Python

Wie die Antwort von @ Matt_Sieker zeigt, lassen sich Fakultäten in Additionen aufteilen - warum das Aufteilen von Aufgaben die Essenz der Programmierung ist. Aber wir können das durch 1 aufschlüsseln!

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)

Ich denke dieser Code garantiert einen SO Fehler, weil

  1. Rekursion - erwärmt es

  2. Jede Ebene generiert Aufrufe zum Multiplizieren

  3. das ruft nach addnumbers auf

  4. das ruft addby1 auf!

Zu viele Funktionen, oder?



1

TI-Basic 84

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

Es funktioniert wirklich :)


1

Javascript

Es ist offensichtlich die Aufgabe eines Programmierers, so wenig wie möglich zu arbeiten und so viele Bibliotheken wie möglich zu nutzen. Daher möchten wir jQuery und math.js importieren . Nun ist die Aufgabe so einfach:

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

1

Python

Mit nur einer geringfügigen Änderung der standardmäßigen rekursiven faktoriellen Implementierung wird sie für n> 10 unerträglich langsam.

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

Bash

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

Versuchen wir es mit der Monte-Carlo-Methode . Wir alle wissen, dass die Wahrscheinlichkeit, dass zwei zufällige n -Permutationen gleich sind, genau 1 / n beträgt ! . Daher können wir nur überprüfen, wie viele Tests benötigt werden (nennen wir diese Nummer b ), bis wir c Treffer erhalten. Dann n! ~ b / c .

Sage sollte auch in Python funktionieren

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

Factorials lassen sich mit den bekannten Kommandozeilen-Tools von bash leicht ermitteln.

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

Wie @Aaron Davies in den Kommentaren erwähnt hat, sieht das viel aufgeräumter aus und wir wollen alle ein schönes und aufgeräumtes Programm, nicht wahr?

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

1
Ich empfehle den stark unterschätzten pasteBefehl:seq 1 $n | paste -sd\* | bc
Aaron Davies

2
@AaronDavies pastesieht aus wie ein normales englisches Wort und ist damit leicht zu merken. Wollen wir das wirklich? ; o)
jippie
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.