Come trovo il fattoriale di un numero positivo?


18

La sfida:

Scrivi un programma o una funzione che inserisce un numero positivo e ne restituisca il fattoriale .

Nota: questa è una domanda di . Si prega di non prendere sul serio la domanda e / o le risposte. Maggiori informazioni qui . Ogni domanda di è anche una domanda di , quindi vince la risposta più votata.


6
Vedi anche il programmatore di The Evolution of Haskell .
Petr Pudlák,

4
-1, scusate, perché stiamo ricevendo un'enorme marea di queste domande di traina del codice e questo non aggiunge davvero nulla di nuovo a loro
Maniglia della porta


Il troll del codice è in procinto di essere rimosso, secondo la posizione ufficiale. Questa domanda ha un discreto numero di voti con molte risposte, molte delle quali sono estremamente votate. Ha ricevuto poco più del 50% dei "elimina" voti nel sondaggio , ma è unico in quanto ha ricevuto così tante risposte e voti, quindi lo sto bloccando per un significato storico.
Maniglia della porta

Risposte:


46

Questo è un problema di calcolo numerico molto semplice che possiamo risolvere con l'approssimazione di Stirling :

Formula di approssimazione di Stirling

Come puoi vedere, quella formula presenta una radice quadrata, che avremo anche bisogno di un modo per approssimare. Sceglieremo il cosiddetto "metodo babilonese" perché è probabilmente il più semplice:

Babylonian method

Si noti che il calcolo della radice quadrata in questo modo è un buon esempio di ricorsione.

Mettere tutto insieme in un programma Python ci offre la seguente soluzione al tuo problema:

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)

Con una semplice modifica il programma sopra può produrre una tabella ordinata di fattoriali:

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

Questo metodo dovrebbe essere sufficientemente preciso per la maggior parte delle applicazioni.


16
+1 La semplicità e l'accuratezza di questo metodo lo rendono un chiaro vincitore
Joe the Person

44

C #

Scusa, ma odio la funzione ricorsiva.

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

1
Tecnicamente, hai soddisfatto il brief! ;) +1 per un breve abuso
WallyWest

36

Giava

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
L'ho provato, molto efficiente. Spedirà con la prossima versione. :)
Johannes,

Oltre al "syndrom dei numeri magici", questa potrebbe effettivamente essere una buona implementazione fintanto che n <13, molto meno stack. Scrivi "case 4: return 4 * 3 * 2;" e avresti una classe decente, molto più veloce di quella vecchia ricorsiva.
Fabinout,

6
@Fabinout, l'implementazione è corretta anche per n> = 13. 13!> Integer.MAX_VALUE.
emory

21

Pitone

Naturalmente il modo migliore per risolvere qualsiasi problema è usare espressioni regolari:

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
Certamente davvero :)
Pierre Arlaud il

15

Haskell

Il codice funzione è un codice efficiente, quindi prova questo.

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

Perché è la pesca a traina:

Riderei per ogni programmatore che ha scritto questo ... L'inefficienza è bella. Probabilmente anche incomprensibile per qualsiasi programmatore Haskell che in realtà non è in grado di scrivere una funzione fattoriale.

Modifica: l'ho pubblicato un po 'di tempo fa adesso, ma ho pensato di chiarire per le persone future e quelle che non sanno leggere Haskell.

Il codice qui prende l'elenco dei numeri da 1 a n, crea l'elenco di tutte le permutazioni di tale elenco e restituisce la lunghezza di tale elenco. Sulla mia macchina ci vogliono circa 20 minuti per 13 !. E poi dovrebbero essere necessarie quattro ore per 14! e poi due giorni e mezzo per 15 !. Tranne che ad un certo punto lì a corto di memoria.

Modifica 2: In realtà probabilmente non esaurirai la memoria a causa del fatto che questo è Haskell (vedi il commento qui sotto). Potresti essere in grado di forzarlo a valutare l'elenco e tenerlo in memoria in qualche modo, ma non so abbastanza sull'ottimizzazione (e non ottimizzazione) di Haskell per sapere esattamente come farlo.


Orribile eppure così elegante, tutto allo stesso tempo.
PLL,

1
Sei sicuro del problema di memoria? In qualsiasi momento, è necessario tenere in memoria: - l'elenco [1..n]. - Una permutazione particolare di [1..n], consegnato a un thunk per il resto delle permutazioni (polinomio in n). - Un accumulatore per la lengthfunzione.
John Dvorak,

Punto giusto, probabilmente non proprio. Non ci ho pensato molto. Aggiungerò un commento in fondo.
Jgon

10

C #

Poiché si tratta di un problema di matematica, ha senso utilizzare un'applicazione appositamente progettata per risolvere i problemi di matematica per eseguire questo calcolo ...

Passo 1:

Installa MATLAB. Una prova funzionerà, credo, ma questo problema estremamente complicato è probabilmente abbastanza importante da meritare l'acquisto della versione completa dell'applicazione.

Passo 2:

Includi il componente MATLAB COM nella tua applicazione.

Passaggio 3:

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

Matlab per studenti parte da $ 100. Le versioni professionali o le licenze del sito possono arrivare a migliaia.
Moshe Katz,

4
Moshe Katz - giustificato perché fattoriale.
Mike H.

9

C #

I fattoriali sono un'operazione matematica di livello superiore che può essere difficile da digerire tutto in una volta. La migliore soluzione in problemi di programmazione come questa, è quella di suddividere una grande attività in attività più piccole.

Ora, n! è definito come 1 * 2 * ... * n, quindi, in sostanza, la moltiplicazione ripetuta e la moltiplicazione non sono altro che un'aggiunta ripetuta. Quindi, tenendo presente ciò, il seguente risolve questo problema:

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

Hai un collo di bottiglia che invia tutto questo tramite una CPU o core, che penso di aver risolto nella mia risposta :-)
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;
}

Trolls:

  • Un modo corretto di calcolo fattoriale al 100% che manca completamente al punto di farlo in modo iterativo o ricorsivo.
  • Non hai idea del perché funzioni e non potresti generalizzarlo per fare qualsiasi altra cosa.
  • Più costoso del semplice calcolo con la matematica dei numeri interi.
  • Il codice "subottimale" più ovvio ( z = n - 1 + 1) è in realtà auto-documentazione se sai cosa sta succedendo.
  • Per troll extra dovrei calcolare p[]usando un calcolo ricorsivo dei coefficienti della serie!

(È l' approssimazione di Lanczos della funzione gamma )


C'è qualche punto - 1 + 1qui? Il mio compilatore lo ottimizza (non è un numero in virgola mobile in cui l'ottimizzazione di codice come questo potrebbe essere pericolosa), quindi sembra non essere necessario.
Konrad Borowski,

4
@xfix: double z = n - 1fa parte dell'approssimazione della funzione gamma. Il + 1è dal rapporto che gamma(n + 1) = n!per intero n.
Ben Jackson,

9

Sappiamo tutti dal college che il modo più efficiente per calcolare una moltiplicazione è attraverso l'uso dei logaritmi. Dopotutto, perché altrimenti le persone dovrebbero usare le tabelle dei logaritmi per centinaia di anni?

Quindi dall'identità a*b=e^(log(a)+log(b))formiamo il seguente codice 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)

Crea un elenco di numeri da 1a x(( +1è necessario perché Python fa schifo) calcola il logaritmo di ciascuno, somma i numeri, aumenta la e alla potenza della somma e infine arrotonda il valore all'intero più vicino (perché Python fa schifo) . Python ha una funzione integrata per il calcolo dei fattoriali, ma funziona solo per i numeri interi, quindi non può produrre grandi numeri (perché Python fa schifo). Ecco perché è necessaria la funzione sopra.

A proposito, un consiglio generale per gli studenti è che se qualcosa non funziona come previsto, è probabilmente perché la lingua fa schifo.


Vorrei poter dare qualche voto extra lì per la descrizione, ma Python fa schifo
Mark K Cowan,

1
Ho riso di "fac you"
Numero 9

8

Sfortunatamente, Javascript non ha un modo integrato per calcolare il fattoriale. Tuttavia, puoi usare il suo significato in combinatoria per determinare il valore:

Il fattoriale di un numero n è il numero di permutazioni di un elenco di quella dimensione.

Quindi, possiamo generare ogni elenco di numeri di n cifre, verificare se si tratta di una permutazione e, in tal caso, incrementare un contatore:

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


Trolls:

  • Tipi di notazione ungherese, snake_case e sigilli inutili. Quanto è cattivo?
  • Ho inventato la mia convenzione per le etichette di salto, incompatibile con l'attuale uso di questa convenzione.
  • Ogni possibile variabile è accidentalmente globale.
  • La soluzione non è O(n), no O(n!), ma O(n^n). Questo da solo sarebbe bastato a qualificarsi qui.
  • Incrementare un numero e poi convertirlo come base-n è un cattivo modo per generare un elenco di sequenze. Anche se volessimo duplicati. La misteriosa rottura per n> 13 non è l'unica ragione.
  • Ovviamente avremmo potuto usare number.toString(base), ma questo non funziona con basi superiori a 36. Sì, ne conosco 36! è molto , ma comunque ...
  • Ho già detto che Javascript aveva l'operatore modulo? Oppure Math.pow? No? Oh bene.
  • Rifiutare di usare ++al di fuori dei for-loops lo rende ancora più misterioso. Inoltre, ==è male.
  • Costrutti di loop senza bretelle profondamente annidati. Inoltre, condizionali nidificati anziché AND. Inoltre, la condizione esterna avrebbe potuto essere evitata terminando il ciclo interno in $i.
  • Le funzioni new Array, document.write(con gli amici) e alert(anziché un prompt o un'etichetta di input) formano un completo triplo di peccati di scelta delle funzioni. Perché, dopo tutto, l'ingresso viene aggiunto in modo dinamico?
  • Gestori di eventi in linea. Oh, e deep piping è un inferno per il debug.
  • Gli attributi non quotati sono divertenti e gli spazi circostanti =li rendono ancora più difficili da leggere.
  • Ho già detto che odio i punti e virgola?

8

Ruby e WolframAlpha

Questa soluzione utilizza l'API REST di WolframAlpha per calcolare il fattoriale, con RestClient per recuperare la soluzione e Nokogiri per analizzarla. Non reinventa alcuna ruota e utilizza tecnologie ben collaudate e popolari per ottenere il risultato nel modo più moderno possibile.

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 è un linguaggio di programmazione funzionale, questo significa che devi usare le funzioni per tutto perché è più veloce.

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
Puoi spiegare?
Mhmd,

7
1 non è una funzione. Il tuo codice è quindi lento.
Pierre Arlaud,

4
@ArlaudPierre r = -~(function(){})lo risolverà sicuramente.
nitro2k01,

4
Sono su una macchina da lavoro, quindi non voglio davvero installare questa lingua. Dove posso trovare una versione che verrà eseguita nel mio browser?
joeytwiddle,

3
Ho un po 'paura di usare Google perché il mio capo ha un account con loro e non voglio che sappia che sto giocando a golf al lavoro. Stavo cercando un'estensione per Firefox che potesse eseguire Javascript, ma non riesco a trovarne una. Alcuni dei miei amici gestiscono Javascript su jsfiddle.net ma usano l'elettricità di qualcun altro che è un po 'come rubare. Mia mamma ha detto che non avrei dovuto frequentare gente del genere, ma sono miei amici, quindi cosa posso fare? Ad ogni modo a volte prende più cremoso di quanto abbia bisogno. Grazie per i suggerimenti, utilizzo Ctrl-Shift-J o K in Firefox. Disclaimer: # comment-trolling
joeytwiddle

5

Utilizzo di Bogo-Sort in Java

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

In realtà funziona molto lentamente e non è preciso per numeri più alti.


4

PERL

Il fattoriale può essere un problema difficile. Una tecnica simile a una mappa / riduzione, proprio come quella utilizzata da Google, può dividere la matematica rinunciando a una serie di processi e raccogliendo i risultati. Questo farà buon uso di tutti quei core o cpus nel tuo sistema in una fredda notte d'inverno.

Salva come f.perl e chmod 755 per assicurarti di poterlo eseguire. Hai installato il Patologically Eclectic Rubbish Lister, vero?

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

Trolls:

  • forchette O (log2 (N)) processi
  • non controlla quante CPU o core hai
  • Nasconde molte conversioni bigint / di testo che si verificano in ogni processo
  • Un ciclo for è spesso più veloce di questo codice

TIL che in perl ARGV[0]è in realtà il primo argomento e non la sceneggiatura!
ThinkChaos

@plg Credo che $ 0 possa contenere il nome file dello script, ma non è lo stesso di $ ARGV [0]
Paul

Sì, è quello che ho letto. Ho appena trovato sorprendente che in Perl non è $ARGV[0]perché la maggior parte delle lingue che conosco ce l'hanno un po '
ThinkChaos

4

Pitone

Solo un algoritmo O (n! * N ^ 2) per trovare il fattoriale. Custodia base gestita. Nessun overflow.

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

Bene, c'è una soluzione semplice in Golfscript. È possibile utilizzare un interprete Golfscript ed eseguire questo codice:

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

Facile eh :) Buona fortuna!


2
Non conosco GolfScript, ma questo mi delude ... Basandomi sugli altri esempi di GolfScript su questo sito, mi sarei aspettato che la risposta fosse!
Mr Lister,

1
Questo è l'operatore di negazione. 0 diventa 1 e tutto il resto diventa 0.
Martijn Courteaux,

3

matematica

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

Non sembra funzionare con numeri maggiori di 11 e fattoriale [11] ha bloccato il mio computer.


3

Rubino

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

Il one-liner più lento che posso immaginare. Per il calcolo sono necessari 2 minuti su un processore i76! .


2

L'approccio corretto per questi difficili problemi matematici è un DSL. Quindi modellerò questo in termini di un linguaggio semplice

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

Per scrivere bene il nostro DSL, è utile vederlo come una monade libera generata dal funzione algebrica

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

Potremmo scrivere questo in Haskell come

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

Lascerò al lettore derivare la banale implementazione di

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

Ora possiamo rimodellare un'operazione per modellare un fattoriale in questo DSL

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

Ora che abbiamo modellato questo, dobbiamo solo fornire una vera funzione di interpretazione per la nostra monade libera.

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

E lascerò il resto della denotazione al lettore.

Per migliorare la leggibilità, a volte è utile presentare un AST concreto del modulo

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

e poi proprio una banale riflessione

reify :: Free b Integer -> AST

e quindi è semplice valutare ricorsivamente l'AST.


2

Pitone

Di seguito è riportata una versione Python della soluzione, che non è limitata al limite a 32 bit (o 64 bit su un sistema molto recente) per i numeri interi in Python. Per aggirare questa limitazione, dovremo usare una stringa come input e output per la factorialroutine e dividere internamente la stringa nelle sue cifre per poter eseguire la moltiplicazione.

Quindi ecco il codice: la getDigitsfunzione divide una stringa che rappresenta un numero nelle sue cifre, così "1234" diventa [ 4, 3, 2, 1 ](l'ordine inverso rende semplicemente le funzioni increasee multiplypiù semplici). La increasefunzione prende un tale elenco e lo aumenta di uno. Come suggerisce il nome, la multiplyfunzione si moltiplica, ad es. multiply([2, 1], [3])Ritorna [ 6, 3 ]perché 12 volte 3 è 36. Funziona allo stesso modo in cui si moltiplicherebbe qualcosa con carta e penna.

Infine, la factorialfunzione utilizza queste funzioni di supporto per calcolare il fattoriale reale, per esempio factorial("9")"362880"come uscita.

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

Appunti

In Python un numero intero non ha un limite, quindi se vuoi farlo manualmente puoi semplicemente farlo

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

C'è anche la math.factorial(n)funzione molto conveniente .

Questa soluzione è ovviamente molto più complessa di quanto deve essere, ma funziona e in effetti illustra come è possibile calcolare il fattoriale nel caso in cui si sia limitati da 32 o 64 bit. Quindi, mentre nessuno crederà che questa sia la soluzione che hai trovato per questo semplice problema (almeno in Python), puoi effettivamente imparare qualcosa.


Non c'è limite ai numeri interi in Python ... giusto? Potrebbe essere necessario spiegarlo meglio.
Riking

@Riking Sì, in Python non c'è limite per gli interi. Ho aggiunto alcune note per renderlo più chiaro.
Brm

2

Pitone

La soluzione più ragionevole è chiaramente quella di controllare tutti i numeri fino a trovare quello che è il fattoriale del numero dato.

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

Una soluzione ricorsiva molto elegante in C

Tutti sanno che le soluzioni più eleganti ai fattoriali sono ricorsive.

Fattoriale:

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

Ma la moltiplicazione può anche essere definita ricorsivamente come aggiunte successive.

Moltiplicazione:

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

E così può anche aggiungere ulteriori incrementi.

aggiunta:

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

In C, possiamo usare ++xe --xgestire i primitivi (x + 1)e (x - 1)rispettivamente, quindi abbiamo tutto definito.

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

Proviamolo:

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

Perfetto, anche se 8! ci è voluto molto tempo per qualche motivo. Vabbè, le soluzioni più eleganti non sono sempre le più veloci. Continuiamo:

$ ./factorial 9

Hmm, ti farò sapere quando tornerà ...


2

Pitone

Come indicato dalla risposta di @ Matt_Sieker, i fattoriali possono essere scomposti in aggiunta, perché, interrompere i compiti è l'essenza della programmazione. Ma possiamo scomporlo in aggiunta per 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)

Penso che questo codice garantisca un errore SO, perché

  1. Ricorsione: lo riscalda

  2. Ogni livello genera chiamate da moltiplicare

  3. che genera chiamate agli addnumber

  4. che genera chiamate ad addby1!

Troppe funzioni, giusto?



1

TI-Basic 84

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

Funziona veramente :)


1

Javascript

Ovviamente il compito di un programmatore è fare il minor lavoro possibile e utilizzare quante più librerie possibile. Pertanto, vogliamo importare jQuery e math.js . Ora, l'attività è semplice come questa:

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

1

Pitone

Con solo una leggera modifica dell'implementazione fattoriale ricorsiva standard, diventa intollerabilmente lenta per 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

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

Proviamo a farlo con il metodo Monte Carlo . Sappiamo tutti che la probabilità di due n casuali -permutazioni siano uguali è esattamente 1 / n! . Quindi possiamo solo controllare quanti test sono necessari (chiamiamo questo numero b ) fino a quando non otteniamo c hit. Quindi, n! ~ b / c .

Sage, dovrebbe funzionare anche in 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

I fattoriali sono facilmente determinabili con i famosi strumenti da riga di comando di bash.

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

Come accennato da @Aaron Davies nei commenti, questo sembra molto più ordinato e tutti vogliamo un programma bello e ordinato, no?

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

1
raccomando il pastecomando altamente sottovalutato :seq 1 $n | paste -sd\* | bc
Aaron Davies

2
@AaronDavies pastesembra una normale parola inglese e con quella facile da ricordare. Lo vogliamo davvero? ; o)
jippie
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.