ฉันจะหาแฟกทอเรียลของจำนวนบวกได้อย่างไร


18

ความท้าทาย:

เขียนโปรแกรมหรือฟังก์ชั่นที่ปัจจัยการผลิตเป็นจำนวนบวกและผลตอบแทนของปัจจัย

หมายเหตุ: นี่เป็นคำถามการกรุณาอย่าใช้คำถามและ / หรือคำตอบอย่างจริงจัง ข้อมูลเพิ่มเติมที่นี่ คำถามการทุกคำถามก็เป็นคำถาม


6
ดูเพิ่มเติมวิวัฒนาการของ Haskell โปรแกรมเมอร์
Petr Pudlák

4
-1, ขออภัยเนื่องจากเราได้รับคำถามมากมายจากการหลอกล่อรหัสและสิ่งนี้ไม่ได้เพิ่มสิ่งใหม่ ๆ ให้กับพวกเขา
Doorknob

ที่เกี่ยวข้อง: codegolf.stackexchange.com/questions/1635/forking-factorials
Paul

การล๊อครหัสอยู่ในขั้นตอนของการถูกลบออกตามท่าทางอย่างเป็นทางการ คำถามนี้มีคะแนนโหวตที่ยุติธรรมพร้อมคำตอบมากมายซึ่งหลายคำถามมีการลงคะแนนอย่างมาก มันได้รับเพียง 50% "ลบ" โหวตในการสำรวจความคิดเห็นแต่มันก็มีความพิเศษที่จะได้รับคำตอบและโหวตมากมายดังนั้นฉันจึงล็อคไว้เพื่อความสำคัญทางประวัติศาสตร์
Doorknob

คำตอบ:


46

นี่เป็นปัญหาการคำนวณเชิงตัวเลขที่ง่ายมากที่เราสามารถแก้ได้ด้วยการประมาณค่าของสเตอร์ลิง :

สูตรการประมาณของสเตอร์ลิง

อย่างที่คุณเห็นสูตรนั้นมีรากที่สองซึ่งเราจะต้องใช้วิธีในการประมาณ เราจะเลือกวิธีการที่เรียกว่า"บาบิโลน"เพราะเป็นวิธีที่ง่ายที่สุด:

วิธีบาบิโลน

โปรดทราบว่าการคำนวณรากที่สองด้วยวิธีนี้เป็นตัวอย่างที่ดีของการเรียกซ้ำ

การนำทุกอย่างมารวมกันในโปรแกรม Python ช่วยให้เราแก้ไขปัญหาของคุณได้ดังต่อไปนี้:

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
ฉันลองแล้ว - มีประสิทธิภาพมาก จะจัดส่งพร้อมการเปิดตัวครั้งต่อไป :)
โยฮันเนส

ข้าง "กลุ่มหมายเลขวิเศษ" นี่อาจเป็นการใช้งานที่ดีตราบใดที่ n <13 มีจำนวนสแต็กน้อยกว่ามาก เขียนมัน "กรณีที่ 4: คืน 4 * 3 * 2;" และคุณจะมีคลาสที่เหมาะสมเร็วกว่าแบบเรียกซ้ำแบบเก่า
Fabinout

6
@Fabinout การนำไปใช้นั้นถูกต้องแม้กระทั่ง n> = 13 13> Integer.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

Haskell

รหัสย่อคือรหัสที่มีประสิทธิภาพดังนั้นให้ลองสิ่งนี้

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

ทำไมมันหมุนรอบ:

ฉันจะหัวเราะเยาะผู้เขียนโค้ดคนนี้ ... ความไร้ประสิทธิภาพนั้นช่างสวยงาม นอกจากนี้ยังอาจเข้าใจไม่ได้สำหรับโปรแกรมเมอร์ Haskell ที่จริง ๆ แล้วไม่สามารถเขียนฟังก์ชันแฟกทอเรียล

แก้ไข: ฉันโพสต์เมื่อครู่นี้ แต่ฉันคิดว่าฉันจะชี้แจงให้ผู้คนในอนาคตและผู้ที่ไม่สามารถอ่าน Haskell ได้

รหัสที่นี่ใช้รายการของหมายเลข 1 ถึง n สร้างรายการเรียงลำดับทั้งหมดของรายการนั้นและส่งกลับความยาวของรายการนั้น บนเครื่องของฉันใช้เวลาประมาณ 20 นาทีสำหรับ 13! จากนั้นควรใช้เวลาสี่ชั่วโมงเป็นเวลา 14 ชั่วโมง! และอีกสองวันครึ่งเป็นเวลา 15! ยกเว้นว่าในบางจุดคุณมีหน่วยความจำไม่เพียงพอ

แก้ไข 2: จริง ๆ แล้วคุณอาจจะไม่เหลือหน่วยความจำเนื่องจากนี่คือ Haskell (ดูความคิดเห็นด้านล่าง) คุณอาจจะสามารถบังคับให้ประเมินรายการและเก็บไว้ในหน่วยความจำได้ แต่ฉันไม่รู้เกี่ยวกับการเพิ่มประสิทธิภาพ (และไม่เพิ่มประสิทธิภาพ) Haskell เพื่อให้รู้ว่าจะทำอย่างไร


น่าเกลียดและสง่างามมากในเวลาเดียวกัน
PLL

1
คุณแน่ใจเกี่ยวกับปัญหาหน่วยความจำหรือไม่? ที่ใดจุดหนึ่งคุณจะต้องถือในหน่วยความจำ: - [1..n]รายการ - หนึ่งการเปลี่ยนแปลงโดยเฉพาะอย่างยิ่งของ[1..n]consed ไป thunk สำหรับส่วนที่เหลือของการเรียงสับเปลี่ยน (พหุนามใน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 รุ่น Professional หรือใบอนุญาตไซต์สามารถเข้าสู่หลักพัน
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;
    }
}

คุณมีคอขวดส่งสิ่งนี้ผ่านซีพียูหรือคอร์หนึ่งซึ่งฉันคิดว่าฉันอาจแก้ไขได้ในคำตอบของฉัน :-)
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% ในการคำนวณแฟคทอเรียลที่พลาดจุดที่ทำซ้ำหรือซ้ำอย่างสมบูรณ์
  • คุณไม่รู้ว่าทำไมมันถึงทำงานได้และไม่สามารถทำให้เป็นเรื่องทั่วไปเพื่อทำสิ่งอื่นได้
  • ค่าใช้จ่ายมากกว่าการคำนวณด้วยเลขจำนวนเต็ม
  • รหัส "suboptimal" ที่ชัดเจนที่สุดz = n - 1 + 1คือการจัดทำเอกสารด้วยตนเองถ้าคุณรู้ว่าเกิดอะไรขึ้น
  • สำหรับการหมุนรอบพิเศษฉันควรคำนวณp[]โดยใช้การคำนวณซ้ำของค่าสัมประสิทธิ์อนุกรม!

(มันเป็นฟังก์ชั่นการประมาณค่าแกมม่าของLanczos )


ที่นี่มีประเด็น- 1 + 1อะไรบ้าง? คอมไพเลอร์ของฉันปรับมันให้เหมาะสม (ไม่ใช่ตัวเลขจุดลอยตัวที่การปรับโค้ดให้เหมาะสมเช่นนี้อาจเป็นอันตรายได้) ดังนั้นจึงดูเหมือนว่าไม่จำเป็น
Konrad Borowski

4
@xfix: double z = n - 1เป็นส่วนหนึ่งของฟังก์ชันแกมมาโดยประมาณ + 1จากความสัมพันธ์ที่gamma(n + 1) = n!สำหรับจำนวนเต็ม n
Ben Jackson

9

เราทุกคนรู้จากวิทยาลัยว่าวิธีที่มีประสิทธิภาพที่สุดในการคำนวณการคูณคือการใช้ลอการิทึม ท้ายที่สุดแล้วทำไมคนอื่นจะใช้ตารางลอการิทึมเป็นร้อย ๆ ปี?

ดังนั้นจากตัวตนa*b=e^(log(a)+log(b))เราจึงสร้างรหัส 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)

มันสร้างรายการของตัวเลขจาก1ถึงx( +1เป็นสิ่งจำเป็นเนื่องจาก Python sucks) คำนวณลอการิทึมของแต่ละจำนวนรวมยก e เพื่ออำนาจของผลรวมและในที่สุดก็รอบค่าเป็นจำนวนเต็มที่ใกล้ที่สุด (เพราะหลาม sucks) . Python มีฟังก์ชันในตัวสำหรับการคำนวณแฟคทอเรียล แต่ใช้ได้กับจำนวนเต็มเท่านั้นดังนั้นจึงไม่สามารถสร้างจำนวนมากได้ (เนื่องจาก Python sucks) นี่คือสาเหตุที่จำเป็นต้องใช้ฟังก์ชันด้านบน

Btw คำแนะนำทั่วไปสำหรับนักเรียนคือหากบางสิ่งบางอย่างไม่ได้ผลตามที่คาดไว้อาจเป็นเพราะภาษาดูด


หวังว่าฉันจะให้คะแนนพิเศษสำหรับคำอธิบาย แต่ Python sucks
Mark K Cowan

1
ฉันหัวเราะที่ "fac you"
หมายเลข 9

8

น่าเสียดายที่ Javascript ไม่มีวิธีการคำนวณแฟคทอเรียลในตัว แต่คุณสามารถใช้ความหมายของมันใน combinatorics เพื่อกำหนดค่าอย่างไรก็ตาม:

แฟคทอเรียลของตัวเลข 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! มีมากแต่ก็ยัง ...
  • ฉันพูดถึง Javascript ว่ามีตัวดำเนินการโมดูลัสหรือไม่ หรือMath.pow? ไม่มี? โอ้ดี
  • การไม่ใช้++นอกลูปทำให้มันลึกลับยิ่งกว่าเดิม นอกจากนี้ยัง==เป็นสิ่งที่ไม่ดี
  • โครงสร้างวนลูปแบบไม่มีโครงที่มีความลึกมาก นอกจากนี้ยังมีเงื่อนไขซ้อนกันแทน AND $iนอกจากนี้สภาพด้านนอกสามารถหลีกเลี่ยงได้โดยการสิ้นสุดภายในวงที่
  • ฟังก์ชั่นnew Array, document.write(กับเพื่อน) และalert(แทนพร้อมท์หรือฉลากการป้อนข้อมูล) รูปแบบ Trifecta สมบูรณ์ของบาปทางเลือกฟังก์ชั่น ทำไมอินพุทจึงถูกเพิ่มเข้ามาแบบไดนามิกหลังจากทั้งหมด?
  • เครื่องมือจัดการเหตุการณ์แบบอินไลน์ โอ้และท่อลึกเป็นนรกที่จะแก้ปัญหา
  • แอตทริบิวต์ที่ไม่ได้กล่าวถึงนั้นสนุกและการเว้นวรรค=ทำให้พวกเขาอ่านยากขึ้น
  • ฉันพูดถึงฉันเกลียดเครื่องหมายอัฒภาคแล้วหรือยัง?

8

Ruby และ WolframAlpha

วิธีการแก้ปัญหานี้ใช้ 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 เพราะเจ้านายของฉันมีบัญชีกับพวกเขาและฉันไม่ต้องการให้เขารู้ว่าฉันกำลังเล่นกอล์ฟในที่ทำงาน ฉันกำลังมองหาส่วนขยายสำหรับ Firefox ที่สามารถเรียกใช้ Javascript ได้ แต่ดูเหมือนจะหาไม่เจอ เพื่อนของฉันบางคนเรียกใช้ Javascript บน jsfiddle.net แต่นั่นเป็นการใช้ไฟฟ้าของคนอื่นซึ่งเหมือนเป็นการขโมย แม่ของฉันบอกว่าฉันไม่ควรไปไหนมาไหนกับคนแบบนั้น แต่พวกเขาเป็นเพื่อนของฉันฉันจะทำอย่างไรดี? อย่างไรก็ตามบางครั้งเธอใช้ครีมเทียมมากกว่าที่เธอต้องการ ขอบคุณสำหรับเคล็ดลับฉันใช้ Ctrl-Shift-J หรือ K ใน Firefox ข้อจำกัดความรับผิดชอบ: # comment-trolling
joeytwiddle

5

ใช้ Bogo-Sort ใน 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;
    }
}

ใช้งานได้จริงช้ามากและไม่แม่นยำสำหรับตัวเลขที่สูงขึ้น


4

PERL

ปัจจัยอาจเป็นปัญหาได้ยาก แผนที่ / ย่อเช่นเทคนิค - เช่นเดียวกับที่ Google ใช้ - สามารถแยกคณิตศาสตร์โดยการแยกกระบวนการและรวบรวมผลลัพธ์ สิ่งนี้จะใช้ประโยชน์จากคอร์หรือซีพียูทั้งหมดในระบบของคุณในคืนฤดูหนาวที่หนาวเหน็บ

บันทึกเป็น f.perl และ chmod 755 เพื่อให้แน่ใจว่าคุณสามารถเรียกใช้ได้ คุณมีการติดตั้งขยะทางพยาธิวิทยาผสมผสานจากลิสเตอร์ใช่หรือไม่?

#!/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 หรือคอร์ของคุณ
  • ซ่อนการแปลงขนาดใหญ่ / ข้อความจำนวนมากที่เกิดขึ้นในทุกขั้นตอน
  • การวนซ้ำมักจะเร็วกว่ารหัสนี้

TIL ที่ใน perl ARGV[0]เป็นอาร์กิวเมนต์แรกไม่ใช่สคริปต์!
ThinkChaos

@plg ฉันเชื่อว่า $ 0 อาจมีชื่อไฟล์สคริปต์ แต่นั่นไม่ใช่ $ ARGV [0]
Paul

ใช่นั่นคือสิ่งที่ฉันอ่าน ฉันเพิ่งพบว่าน่าแปลกใจที่ใน perl ไม่ใช่$ARGV[0]เพราะภาษาส่วนใหญ่ฉันรู้ว่ามันมี
นิดหน่อย

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 และแฟคทอเรียล [11] ทำให้คอมพิวเตอร์ของฉันแข็ง


3

ทับทิม

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

ซับที่ช้าที่สุดที่ฉันจินตนาการได้ มันต้องใช้เวลา 2 นาทีใน i7 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 ของเราเป็นสิ่งที่ดีหากเรามองว่ามันเป็น monad ฟรีที่สร้างขึ้นโดย functor เกี่ยวกับพีชคณิต

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

ตอนนี้เราได้สร้างแบบจำลองนี้ขึ้นมาเราเพียงแค่ต้องจัดหาฟังก์ชั่นการตีความที่เกิดขึ้นจริงสำหรับ monad ฟรีของเรา

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

และฉันจะทิ้งส่วนที่เหลือของ denotation ไปยังผู้อ่าน

ในการปรับปรุงความสามารถในการอ่านบางครั้งก็มีประโยชน์ในการนำเสนอ AST ที่เป็นรูปธรรมของแบบฟอร์ม

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

และจากนั้นก็เป็นภาพสะท้อนเล็กน้อย

reify :: Free b Integer -> AST

แล้วมันก็ตรงไปตรงมาเพื่อประเมิน AST ซ้ำ ๆ


2

หลาม

ด้านล่างนี้เป็นรุ่น Python ของการแก้ปัญหาซึ่งไม่ จำกัด เพียง 32 บิต (หรือ 64 บิตในระบบล่าสุด) สำหรับตัวเลขจำนวนเต็มใน Python ในการหลีกเลี่ยงข้อ จำกัด นี้เราจะใช้สตริงเป็นอินพุตและเอาต์พุตสำหรับfactorialรูทีนและแบ่งสตริงภายในเป็นตัวเลขเพื่อให้สามารถทำการคูณได้

นี่คือรหัส: getDigitsฟังก์ชั่นจะแยกสตริงที่แสดงตัวเลขเป็นหลักดังนั้น "1234" จึงกลายเป็น[ 4, 3, 2, 1 ](ลำดับย้อนกลับทำให้ฟังก์ชันincreaseและ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 บิต ดังนั้นในขณะที่ไม่มีใครเชื่อว่านี่เป็นวิธีการแก้ปัญหาที่คุณคิดขึ้นมาสำหรับปัญหาง่ายๆ (อย่างน้อยใน Python) คุณสามารถเรียนรู้บางสิ่งได้


ไม่มีการ จำกัด จำนวนเต็มใน Python ... ใช่มั้ย คุณอาจต้องอธิบายเรื่องนี้ให้ดีขึ้น
Riking

@Riking ใช่ใน python ไม่มีข้อ จำกัด สำหรับจำนวนเต็ม ฉันได้เพิ่มบันทึกย่อบางส่วนเพื่อให้ชัดเจนยิ่งขึ้น
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

ทุกคนรู้ว่าทางออกที่ดีที่สุดสำหรับแฟคทอเรียลนั้นวนเวียนอยู่ซ้ำ

factorial:

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. ซึ่งสร้างสายเพื่อเพิ่มหมายเลข

  4. ซึ่งสร้างสายเพื่อ addby1!

ฟังก์ชั่นมากเกินไปใช่ไหม



1

TI-Basic 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

ลองที่จะทำมันด้วยมอนติคาร์โลวิธี เราทุกคนรู้ว่าความน่าจะเป็นของการสุ่มสองn- permutations เท่ากับเท่ากับ1 / n! . ดังนั้นเราสามารถตรวจสอบจำนวนการทดสอบที่ต้องการ (เรียกหมายเลขนี้ ) จนกว่าเราจะได้รับความนิยมc จากนั้นn! ~ B / C

ปราชญ์ควรทำงานใน 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

ทุบตี

แฟกทอรีสามารถกำหนดได้อย่างง่ายดายด้วยเครื่องมือบรรทัดคำสั่งที่รู้จักกันดีจากการทุบตี

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
ผมขอแนะนำให้สูง underrated pasteคำสั่ง:seq 1 $n | paste -sd\* | bc
แอรอนเดวีส์

2
@AaronDavies pasteดูเหมือนคำภาษาอังกฤษทั่วไปและง่ายต่อการจดจำ เราต้องการสิ่งนั้นจริงหรือ ; o)
jippie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.