Finding the LCM of a range of numbers

前端 未结 14 734
时光说笑
时光说笑 2020-12-08 05:03

I read an interesting DailyWTF post today, \"Out of All The Possible Answers...\" and it interested me enough to dig up the original forum post where it was submitted. This

相关标签:
14条回答
  • 2020-12-08 05:45

    One-liner in Haskell.

    wideLCM = foldl lcm 1
    

    This is what I used for my own Project Euler Problem 5.

    0 讨论(0)
  • 2020-12-08 05:47

    In Haskell:

    listLCM xs =  foldr (lcm) 1 xs
    

    Which you can pass a list eg:

    *Main> listLCM [1..10]
    2520
    *Main> listLCM [1..2518]
    266595767785593803705412270464676976610857635334657316692669925537787454299898002207461915073508683963382517039456477669596355816643394386272505301040799324518447104528530927421506143709593427822789725553843015805207718967822166927846212504932185912903133106741373264004097225277236671818323343067283663297403663465952182060840140577104161874701374415384744438137266768019899449317336711720217025025587401208623105738783129308128750455016347481252967252000274360749033444720740958140380022607152873903454009665680092965785710950056851148623283267844109400949097830399398928766093150813869944897207026562740359330773453263501671059198376156051049807365826551680239328345262351788257964260307551699951892369982392731547941790155541082267235224332660060039217194224518623199770191736740074323689475195782613618695976005218868557150389117325747888623795360149879033894667051583457539872594336939497053549704686823966843769912686273810907202177232140876251886218209049469761186661055766628477277347438364188994340512556761831159033404181677107900519850780882430019800537370374545134183233280000
    
    0 讨论(0)
  • 2020-12-08 05:54

    There's a fast solution to this, so long as the range is 1 to N.

    The key observation is that if n (< N) has prime factorization p_1^a_1 * p_2^a_2 * ... p_k * a_k, then it will contribute exactly the same factors to the LCM as p_1^a_1 and p_2^a_2, ... p_k^a_k. And each of these powers is also in the 1 to N range. Thus we only need to consider the highest pure prime powers less than N.

    For example for 20 we have

    2^4 = 16 < 20
    3^2 = 9  < 20
    5^1 = 5  < 20
    7
    11
    13
    17
    19
    

    Multiplying all these prime powers together we get the required result of

    2*2*2*2*3*3*5*7*11*13*17*19 = 232792560
    

    So in pseudo code:

    def lcm_upto(N):
      total = 1;
      foreach p in primes_less_than(N):
        x=1;
        while x*p <= N:
          x=x*p;
        total = total * x
      return total
    

    Now you can tweak the inner loop to work slightly differently to get more speed, and you can precalculate the primes_less_than(N) function.

    EDIT:

    Due to a recent upvote I decideded to revisit this, to see how the speed comparison with the other listed algorithms went.

    Timing for range 1-160 with 10k iterations, against Joe Beibers and Mark Ransoms methods are as follows:

    Joes : 1.85s Marks : 3.26s Mine : 0.33s

    Here's a log-log graph with the results up to 300.

    A log-log graph with the results

    Code for my test can be found here:

    import timeit
    
    
    def RangeLCM2(last):
        factors = range(last+1)
        result = 1
        for n in range(last+1):
            if factors[n] > 1:
                result *= factors[n]
                for j in range(2*n, last+1, n):
                    factors[j] /= factors[n]
        return result
    
    
    def lcm(a,b):
        gcd, tmp = a,b
        while tmp != 0:
            gcd,tmp = tmp, gcd % tmp
        return a*b/gcd
    
    def EuclidLCM(last):
        return reduce(lcm,range(1,last+1))
    
    primes = [
     2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 
     31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 
     73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 
     127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 
     179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 
     233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 
     283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 
     353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 
     419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 
     467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 
     547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 
     607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 
     661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 
     739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 
     811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 
     877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 
     947, 953, 967, 971, 977, 983, 991, 997 ]
    
    def FastRangeLCM(last):
        total = 1
        for p in primes:
            if p>last:
                break
            x = 1
            while x*p <= last:
                x = x * p
            total = total * x
        return total
    
    
    print RangeLCM2(20)
    print EculidLCM(20)
    print FastRangeLCM(20)
    
    print timeit.Timer( 'RangeLCM2(20)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(20)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(20)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(40)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(40)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(40)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(60)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(60)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(60)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(80)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(80)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(80)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(100)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(100)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(100)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(120)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(120)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(120)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(140)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(140)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(140)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    print timeit.Timer( 'RangeLCM2(160)', "from __main__ import RangeLCM2").timeit(number=10000)
    print timeit.Timer( 'EuclidLCM(160)', "from __main__ import EuclidLCM" ).timeit(number=10000)
    print timeit.Timer( 'FastRangeLCM(160)', "from __main__ import FastRangeLCM" ).timeit(number=10000)
    
    0 讨论(0)
  • 2020-12-08 05:56

    The LCM of one or more numbers is the product of all of the distinct prime factors in all of the numbers, each prime to the power of the max of all the powers to which that prime appears in the numbers one is taking the LCM of.

    Say 900 = 2^3 * 3^2 * 5^2, 26460 = 2^2 * 3^3 * 5^1 * 7^2. The max power of 2 is 3, the max power of 3 is 3, the max power of 5 is 1, the max power of 7 is 2, and the max power of any higher prime is 0. So the LCM is: 264600 = 2^3 * 3^3 * 5^2 * 7^2.

    0 讨论(0)
  • 2020-12-08 05:59

    The answer does not require any fancy footwork at all in terms of factoring or prime powers, and most certainly does not require the Sieve of Eratosthenes.

    Instead, you should calculate the LCM of a single pair by computing the GCD using Euclid's algorithm (which does NOT require factorization, and in fact is significantly faster):

    
    def lcm(a,b):
        gcd, tmp = a,b
        while tmp != 0:
            gcd,tmp = tmp, gcd % tmp
        return a*b/gcd
    

    then you can find the total LCM my reducing the array using the above lcm() function:

    
    reduce(lcm, range(1,21))
    
    0 讨论(0)
  • 2020-12-08 06:00

    This is probably the cleanest, shortest answer (both in terms of lines of code) that I've seen so far.

    def gcd(a,b): return b and gcd(b, a % b) or a
    def lcm(a,b): return a * b / gcd(a,b)
    
    n = 1
    for i in xrange(1, 21):
        n = lcm(n, i)
    

    source : http://www.s-anand.net/euler.html

    0 讨论(0)
提交回复
热议问题