양수의 계승을 찾으려면 어떻게합니까?


18

도전 과제 :

양수를 입력하고 계승을 반환하는 프로그램이나 함수를 작성하십시오 .

참고 : 이것은 질문입니다. 질문 및 / 또는 답변을 진지하게 받아들이지 마십시오. 자세한 내용은 여기를 참조 하십시오 . 모든 질문도 질문이므로 가장 높은 투표 응답이 이깁니다.



4
-1, 죄송합니다. 이러한 코드 트롤링 문제로 인해 많은 문제가 발생하여 실제로 새로운 내용이 추가되지는 않습니다.
Doorknob


공식 입장 에 따라 코드 트롤링을 제거하는 중 입니다. 이 질문에는 많은 답변이 포함 된 공정한 정도의 투표권이 있으며 그 중 다수는 매우 높은 투표율을 보입니다. 여론 조사 에서 50 % 이상의 "삭제"투표를 받았지만, 많은 답변과 투표를 받았다는 점에서 독특합니다.
Doorknob

답변:


46

이것은 Stirling의 근사치로 해결할 수있는 매우 간단한 수치 계산 문제입니다 .

스털링의 근사 공식

보시다시피, 그 공식은 제곱근을 특징으로하며, 근사법도 필요합니다. 우리는 소위 "바빌로니아 방법" 을 선택할 것입니다.

바빌로니아 방법

이 방법으로 제곱근을 계산하는 것이 재귀의 좋은 예입니다.

파이썬 프로그램에 모두 통합하면 문제에 대한 다음 해결책을 얻을 수 있습니다.

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)

간단한 수정으로 위의 프로그램은 깔끔한 계승 테이블을 출력 할 수 있습니다.

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

이 방법은 대부분의 응용 분야에서 충분히 정확해야합니다.


16
+1이 방법의 단순성과 정확성은 확실한 승자입니다
Joe the Person

44

씨#

죄송하지만 재귀 기능이 싫습니다.

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

1
기술적으로, 당신은 간단한 내용을 만족 시켰습니다! ;) 잠깐 남용으로 +1
WallyWest

36

자바

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
나는 그것을 시도했다-매우 효율적이다. 다음 릴리스와 함께 제공됩니다. :)
Johannes

"매직 숫자 syndrom"외에도 n <13 인 스택보다 훨씬 적은 실제 구현이 될 수 있습니다. "사례 4 : return 4 * 3 * 2;"라고 적으십시오. 그리고 당신은 예전의 재귀 클래스보다 훨씬 빠른 알맞은 클래스를 가질 것입니다.
Fabinout

6
@ Fabinout, 구현은 n> = 13에서도 정확합니다. 13!> 정수 .MAX_VALUE.
emory

21

파이썬

물론 문제를 해결하는 가장 좋은 방법은 정규식을 사용하는 것입니다.

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
물론 :)
Pierre Arlaud

15

하스켈

짧은 코드는 효율적인 코드이므로 이것을 시도하십시오.

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

왜 트롤링을 하는가 :

나는 이것을 쓴 코더를 비웃을 것이다. 또한 실제로 계승 함수를 작성할 수없는 하스켈 프로그래머에게는 이해할 수 없습니다.

편집 : 나는 이것을 얼마 전에 게시했지만 미래의 사람들과 Haskell을 읽을 수없는 사람들을 위해 명확하게 생각한다고 생각했습니다.

여기서 코드는 1에서 n까지의 숫자 목록을 가져 와서 해당 목록의 모든 순열 목록을 작성하고 해당 목록의 길이를 리턴합니다. 내 컴퓨터에서는 13 분 동안 20 분 정도 걸립니다!. 그리고 14 시간 동안 4 시간이 걸립니다! 그리고 15 일 동안 이틀 반! 그 시점의 어느 시점에서 당신은 메모리가 부족합니다.

편집 2 : 실제로 Haskell이기 때문에 메모리가 부족하지 않을 것입니다 (아래 주석 참조). 어떻게 든 목록을 평가하고 메모리에 보관하도록 강요 할 수는 있지만 Haskell을 최적화하는 방법에 대해 정확히 알지 못합니다.


동시에 끔찍하면서도 우아합니다.
PLL

1
메모리 문제가 확실합니까? 어느 시점에서든 메모리를 보유해야합니다.-list [1..n]. -의 하나의 특정 순열은 [1..n]나머지 순열에 대한 썽 크로 간주됩니다 (다항식 n). - length기능을 위한 누산기 .
John Dvorak

아마도 사실은 아닐 것입니다. 그것에 대해 너무 많이 생각하지 않았습니다. 하단에 설명을 추가하겠습니다.
jgon

10

씨#

이것은 수학 문제이므로 수학 문제를 해결하도록 특별히 설계된 응용 프로그램을 사용하여이 계산을 수행하는 것이 좋습니다.

1 단계:

MATLAB을 설치하십시오. 시험판은 효과가있을 것이지만,이 매우 복잡한 문제는 정식 버전의 응용 프로그램을 구매할 가치가 있다고 생각됩니다.

2 단계:

응용 프로그램에 MATLAB COM 구성 요소를 포함하십시오.

3 단계 :

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

학생들을위한 Matlab은 $ 100부터 시작합니다. 프로페셔널 버전 또는 사이트 라이센스는 수천 가지로 나아갈 수 있습니다.
Moshe Katz

4
Moshe Katz-계승 때문에 정당화되었습니다.
Mike H.

9

씨#

계승은 한 번에 모두 소화하기 어려울 수있는 상위 수준의 수학 연산입니다. 이와 같은 프로그래밍 문제의 가장 좋은 해결책은 하나의 큰 작업을 작은 작업으로 나누는 것입니다.

자, n! 는 1 * 2 * ... * n으로 정의되므로 본질적으로 반복 곱셈이며 곱셈은 반복 된 덧셈에 지나지 않습니다. 따라서이를 염두에두고 다음과 같은 문제가 해결됩니다.

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

하나의 CPU 또는 코어를 통해이 모든 것을 보내는 병목 현상이 있습니다. 내 대답에서 해결 된 것으로 생각됩니다 :-)
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;
}

트롤 :

  • 계승을 반복적으로 또는 재귀 적으로 수행하는 요점을 완전히 놓치는 100 % 정확한 계승 계산 방법.
  • 왜 작동하는지 알 수 없으며 다른 작업을 수행하기 위해 일반화 할 수 없습니다.
  • 정수 수학으로 계산하는 것보다 비용이 많이 듭니다.
  • 가장 확실한 "차선책"코드 ( z = n - 1 + 1)는 실제로 무슨 일이 일어나고 있는지 알고 있다면 자체 문서화입니다.
  • 추가 트롤링을 위해서는 p[]시리즈 계수의 재귀 계산을 사용하여 계산해야합니다 !

( 감마 함수Lanczos 근사치입니다 )


- 1 + 1여기에 어떤 점이 있습니까? 내 컴파일러는 최적화합니다 (이와 같은 코드 최적화가 위험 할 수있는 부동 소수점 숫자는 아닙니다). 필요하지 않은 것으로 보입니다.
Konrad Borowski

4
@xfix : double z = n - 1는 감마 함수의 근사치의 일부입니다. 는 + 1그 관계로부터 인 gamma(n + 1) = n!정수 N.
벤 잭슨

9

우리는 대학에서 곱셈을 계산하는 가장 효율적인 방법은 로그를 사용하는 것임을 알고 있습니다. 결국 사람들이 왜 수백 년 동안 로그 테이블을 사용합니까?

따라서 a*b=e^(log(a)+log(b))우리 는 정체성 에서 다음과 같은 파이썬 코드를 형성합니다.

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)

그것은에서 번호의 목록을 만듭니다 1으로 x합니다 (이, +1각각의 로그를 계산 파이썬 짜증 때문에 필요) 숫자를 요약, 합계의 힘에 전자를 제기하고 마지막으로 (파이썬 짜증 때문에) 가장 가까운 정수로 값을 반올림 . 파이썬에는 계승을 계산하는 함수가 내장되어 있지만 정수에서만 작동하므로 큰 숫자를 생성 할 수 없습니다 (파이썬이 빨기 때문에). 이것이 바로 위의 기능이 필요한 이유입니다.

학생들에게 일반적인 팁인 Btw는 무언가 예상대로 작동하지 않으면 언어가 짜증나 기 때문일 수 있습니다.


설명에 대한 추가 투표를 할 수 있기를 바랍니다. 그러나 파이썬은 짜증납니다
Mark K Cowan

1
나는 "fac you"에 웃었다
Number9

8

불행히도 Javascript에는 계승을 계산하는 기본 제공 방법이 없습니다. 그럼에도 불구하고 조합론에서 그 의미를 사용하여 값을 결정할 수 있습니다.

숫자 n의 계승은 해당 크기 목록의 순열 수입니다.

따라서 모든 n 자리 숫자 목록을 생성하고 순열인지 확인하고 그렇다면 카운터를 증가시킵니다.

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


트롤 :

  • 헝가리 표기법, snake_case 불필요한 sigils 를 입력 합니다. 그게 얼마나 악한가요?
  • 이 규칙의 현재 사용과 호환되지 않는 점프 레이블에 대한 자체 규칙을 발명했습니다.
  • 가능한 모든 변수는 실수로 전역입니다.
  • 이 솔루션은 아니다 O(n),하지 O(n!),하지만 O(n^n). 이것만으로도 여기서 자격을 갖추었을 것입니다.
  • 숫자를 증가시킨 다음 base-n으로 변환하는 것은 시퀀스 목록을 생성하는 나쁜 방법입니다. 우리가 중복을 원하더라도. n> 13을 신비롭게 깨는 것이 유일한 이유는 아닙니다.
  • 물론 우리는 사용할 수 number.toString(base)있지만 36 이상의 기지에서는 효과가 없습니다. 예, 36을 알고 있습니다! A는 많이 하지만 여전히, ...
  • Javascript에 모듈러스 연산자가 있다고 언급 했습니까? 아니면 Math.pow? 아니? 오 잘
  • ++for-loops 외부 에서 사용을 거부하면 더욱 신비하게됩니다. 또한 ==나쁘다.
  • 깊게 중첩 된 브레이스리스 반복 구조. 또한 AND 대신 중첩 된 조건문. 또한에서 내부 루프를 종료하여 외부 조건을 피할 수있었습니다 $i.
  • 기능 new Array, document.write(친구와 함께)와 alert(대신 프롬프트 또는 입력 라벨)은 기능 선택 죄의 완전한 trifecta에를 형성한다. 결국 입력이 동적으로 추가되는 이유는 무엇입니까?
  • 인라인 이벤트 핸들러. 아, 그리고 깊은 배관은 디버그하기가 어렵다.
  • 인용되지 않은 속성은 재미 있고, 주변의 공백은 =읽기가 더 어렵습니다.
  • 내가 세미콜론을 싫어한다고 언급 했습니까?

8

루비와 볼프람

이 솔루션은 WolframAlpha REST API를 사용하여 계승을 계산하고 RestClient는 솔루션을 가져오고 Nokogiri는 솔루션을 구문 분석합니다. 휠을 재발 명하지 않으며 잘 테스트되고 널리 사용되는 기술을 사용하여 가장 현대적인 방법으로 결과를 얻습니다.

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는 함수형 프로그래밍 언어이므로 모든 것이 더 빠르기 때문에 함수를 사용해야합니다.

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
설명 할 수 있습니까?
Mhmd

7
1은 기능이 아닙니다. 따라서 코드가 느립니다.
Pierre Arlaud

4
@ArlaudPierre r = -~(function(){})는 확실히 그것을 해결할 것입니다.
nitro2k01

4
나는 작업 기계를 사용하고 있으므로이 언어를 실제로 설치하고 싶지 않습니다. 브라우저에서 실행될 버전을 어디에서 찾을 수 있습니까?
joeytwiddle

3
상사가 계정을 가지고 있기 때문에 Google을 사용하는 것이 조금 무섭습니다. 직장에서 골프를하고 있다는 것을 알고 싶지 않습니다. Javascript를 실행할 수있는 Firefox 용 확장 프로그램을 찾고 있었지만 찾을 수없는 것 같습니다. 내 친구 중 일부는 jsfiddle.net에서 Javascript를 실행하지만 다른 사람의 전기를 사용하여 도둑질과 비슷합니다. 우리 엄마는 그런 사람들과 어울리지 말아야한다고 말했지만 그들은 내 친구이므로 어떻게해야합니까? 어쨌든 그녀는 때때로 그녀가 필요로하는 것보다 더 많은 크림을 필요로합니다. 팁 덕분에 Firefox에서 Ctrl-Shift-J 또는 K를 사용합니다. 면책 조항 : # comment-trolling
joeytwiddle

5

Java에서 Bogo-Sort 사용

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

이것은 실제로 매우 느리게 작동하며 숫자가 높을 때는 정확하지 않습니다.


4

계승은 어려운 문제 일 수 있습니다. Google이 사용하는 것처럼지도 / 축소와 같은 기술은 여러 프로세스를 분기하고 결과를 수집하여 수학을 나눌 수 있습니다. 추운 겨울 밤에 시스템의 모든 코어 또는 CPU를 잘 활용할 수 있습니다.

f.perl 및 chmod 755로 저장하여 실행할 수 있는지 확인하십시오. Pathologically Eclectic Rubbish Lister가 설치되어 있습니까?

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

트롤 :

  • 포크 O (log2 (N)) 프로세스
  • 가지고있는 CPU 또는 코어 수를 확인하지 않습니다
  • 모든 프로세스에서 발생하는 많은 bigint / text 변환을 숨 깁니다.
  • for 루프는 종종이 코드보다 빠릅니다.

ARGV[0]에서 실제로 스크립트가 아닌 첫 번째 인수 라는 것을 TIL !
ThinkChaos

@plg $ 0에 스크립트 파일 이름이 포함되어 있다고 생각하지만 $ ARGV [0]과 동일하지 않습니다.
Paul

그렇습니다, 그것은 내가 읽은 것입니다. 나는 단지 $ARGV[0]대부분의 언어가 거기에 약간의 언어를 가지고 있기 때문에 펄에서 그렇지 않다는 것이 놀랍다는 것을 발견했다
ThinkChaos

4

파이썬

계승을 구하기위한 O (n! * n ^ 2) 알고리즘. 기본 케이스 처리. 오버플로가 없습니다.

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에는 쉬운 해결책이 있습니다. Golfscript 인터프리터를 사용하여 다음 코드를 실행할 수 있습니다.

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

쉬운 허 :) 행운을 빕니다!


2
나는 GolfScript를 모른다. 그러나 이것은 나를 실망시킨다.이 사이트의 다른 GolfScript 예제에 근거하여, 나는 대답이 될 것이라고 예상했을 것이다!
Mr Lister

1
그것은 부정 연산자입니다. 0은 1이되고 나머지는 0이됩니다.
Martijn Courteaux

3

매스 매 티카

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

11보다 큰 숫자에서는 작동하지 않는 것 같으며 factorial [11]은 내 컴퓨터를 멈췄습니다.


3

루비

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

내가 상상할 수있는 가장 느린 1 개의 강선. i7 프로세서에서 계산하는 데 2 ​​분이 걸립니다 6!.


2

이러한 어려운 수학 문제에 대한 올바른 접근 방식은 DSL입니다. 간단한 언어로 모델링하겠습니다

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

DSL을 멋지게 쓰려면 대수 펑터가 생성 한 무료 모나드로 보는 것이 도움이됩니다

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

이것을 Haskell에서 다음과 같이 쓸 수 있습니다.

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

나는 그것을 사소한 구현을 도출하기 위해 독자에게 맡길 것이다.

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

이제이 DSL에서 계승을 모델링하는 연산을 설명 할 수 있습니다.

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

우리는 이것을 모델링 했으므로, 무료 모나드에 대한 실제 해석 기능을 제공하면됩니다.

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

그리고 나머지 주석은 독자에게 맡기겠습니다.

가독성을 높이려면 구체적인 AST 형식을 제시하는 것이 도움이 될 수 있습니다.

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

그리고 사소한 반사

reify :: Free b Integer -> AST

그런 다음 AST를 재귀 적으로 평가하는 것이 간단합니다.


2

파이썬

다음은 Python 버전의 솔루션으로, Python의 정수에 대한 32 비트 (또는 최신 시스템의 64 비트) 제한으로 제한되지 않습니다. 이 한계를 극복하기 위해 factorial루틴에 대한 입력 및 출력으로 문자열을 사용하고 곱셈을 수행 할 수 있도록 문자열을 숫자로 내부 분할합니다.

코드는 다음과 같습니다.이 getDigits함수는 숫자를 나타내는 문자열을 숫자로 분리하므로 "1234"가됩니다 [ 4, 3, 2, 1 ](역순으로 increaseand multiply함수가 더 간단 해집니다). increase함수는 이러한리스트 및 하나만큼 증가 걸립니다. 이름에서 알 수 있듯이, multiply함수의 곱, 예를 들어 multiply([2, 1], [3])수익률이 [ 6, 3 ]12 회 (3) 같은 방법으로 (36)이 작품 때문에 당신이 펜과 종이에 거는 뭔가를하는 것처럼.

이어서 마지막으로, factorial예를위한 기능은 실제 계승을 계산하도록 이러한 헬퍼 기능을 사용하여 factorial("9")제공 "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")

노트

파이썬에서는 정수에 제한이 없으므로 수동으로 수행하려면 수동으로 수행하십시오.

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

매우 편리한 math.factorial(n)기능도 있습니다.

이 솔루션은 필요 이상으로 훨씬 더 복잡하지만 실제로 작동하며 실제로 32 또는 64 비트로 제한되는 경우 계승을 계산할 수있는 방법을 보여줍니다. 따라서 아무도 이것이 (최소한 파이썬에서는)이 간단한 문제에 대한 해결책이라고 생각하지 않지만 실제로 무언가를 배울 수 있습니다.


파이썬에서는 정수에 제한이 없습니다 ... 맞습니까? 이것을 더 잘 설명해야 할 수도 있습니다.
Riking

@Riking 네, 파이썬에서는 정수에 대한 제한이 없습니다. 좀 더 명확하게하기 위해 몇 가지 메모를 추가했습니다.
brm

2

파이썬

가장 합리적인 해결책은 주어진 숫자의 계승 인 것을 찾을 때까지 모든 숫자를 명확하게 확인하는 것입니다.

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에서 가장 우아한 재귀 솔루션

모든 사람은 계승에 대한 가장 우아한 솔루션이 재귀 적이라는 것을 알고 있습니다.

계승:

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

그러나 곱셈은 연속적인 추가로 재귀 적으로 정의 될 수도 있습니다.

곱셈:

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

또한 연속 증분으로 추가 할 수 있습니다.

부가:

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

에서은 C, 우리가 사용할 수 있습니다 ++x--x프리미티브를 처리하기 위해 (x + 1)그리고 (x - 1)우리가 모든 것을 정의하므로, 각각.

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

사용해 봅시다 :

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

8이지만 완벽합니다! 어떤 이유로 오랜 시간이 걸렸습니다. 글쎄, 가장 우아한 솔루션이 항상 가장 빠른 것은 아닙니다. 계속하자 :

$ ./factorial 9

흠, 돌아올 때 알려 줄게 ..


2

파이썬

@Matt_Sieker의 답변에서 알 수 있듯이 계승은 추가로 나눌 수 있습니다. 이유는 작업을 나누는 것이 프로그래밍의 핵심입니다. 그러나 우리는 이것을 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)

이 코드 는 SO 오류를 보장 한다고 생각합니다.

  1. 재귀-예열

  2. 각 계층은 곱하기 호출을 생성합니다

  3. addnumbers에 대한 호출을 생성하는

  4. addby1에 대한 호출을 생성합니다!

기능이 너무 많죠?



1

TI 기본 84

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

이것은 진짜 작동한다 :)


1

자바 스크립트

프로그래머가해야 할 일은 가능한 한 적은 노력을 기울이고 가능한 많은 라이브러리를 사용하는 것입니다. 따라서 jQuery math.js 를 가져오고 싶습니다 . 이제 작업은 다음과 같이 간단합니다.

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

1

파이썬

표준 재귀 적 팩토리얼 구현을 약간 수정하면 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

세게 때리다

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

Monte Carlo Method로 해보자 . 우리는 두 개의 랜덤 n 순열이 같을 확률 이 정확히 1 / n 이라는 것을 알고 있습니다 ! . 따라서 c 적중 을 얻을 때까지 몇 번의 테스트가 필요한지 확인할 수 있습니다 (이 숫자를 호출하십시오 b ) . 그런 다음 n! ~ b / c .

세이지, 파이썬에서도 작동

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의 잘 알려진 명령 줄 도구를 사용하여 계승을 쉽게 결정할 수 있습니다.

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

댓글에 @Aaron Davies가 언급했듯이, 이것은 훨씬 깔끔해 보이고 우리 모두는 멋지고 깔끔한 프로그램을 원합니다.

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

1
나는 과소 평가 된 paste명령을 추천한다 :seq 1 $n | paste -sd\* | bc
Aaron Davies

2
@AaronDavies paste는 일반적인 영어 단어처럼 보이며 기억하기 쉽습니다. 우리는 정말로 그것을 원합니까? ; o)
jippie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.