C++ algorithm to calculate least common multiple for multiple numbers
Asked Answered
B

16

30

Is there a C++ algorithm to calculate the least common multiple for multiple numbers, like lcm(3,6,12) or lcm(5,7,9,12)?

Bergren answered 19/11, 2010 at 22:15 Comment(2)
Why? lcm(int, int) is easily scalable. You can even do it yourself.Betel
Is it for school or for a high performance application?Betel
I
54

You can use std::accumulate and some helper functions:

#include <iostream>
#include <numeric>

int gcd(int a, int b)
{
    for (;;)
    {
        if (a == 0) return b;
        b %= a;
        if (b == 0) return a;
        a %= b;
    }
}

int lcm(int a, int b)
{
    int temp = gcd(a, b);

    return temp ? (a / temp * b) : 0;
}

int main()
{
    int arr[] = { 5, 7, 9, 12 };

    int result = std::accumulate(arr, arr + 4, 1, lcm);

    std::cout << result << '\n';
}
Innovation answered 19/11, 2010 at 22:25 Comment(6)
Learned about std::accumulate after reading this answer. Thanks for sharing!Sensual
for(;;)? why do you confuse?Yeomanry
@FerencDajka: for (;;) {} is a very common C and C++ idiom for an infinite loop. I use it partly out of habit and because some compilers emit a warning for while (true) {}. See this related questionInnovation
Slightly optimized: int result = std::accumulate(arr + 1, arr + 4, arr[0], lcm);Abeabeam
Ternary operator to get around division by zero. Never would've thought of that.Mullin
Just mentioning, in the meantime there's std::lcm which you can use to replace the hand-written lcm function in this answer.Crave
R
18

boost provides functions for calculation lcm of 2 numbers (see here)

Then using the fact that

lcm(a,b,c) = lcm(lcm(a,b),c)

You can easily calculate lcm for multiple numbers as well

Reproof answered 19/11, 2010 at 22:17 Comment(2)
I see here a good exercise to practice variadic template and write a small wrapper for any number of args. :-)Bloodred
@Hiura, see my answer belowIvaivah
I
9

As of C++17, you can use std::lcm.

And here is a little program that shows how to specialize it for multiple parameters

#include <numeric>
#include <iostream>

namespace math {

    template <typename M, typename N>
    constexpr auto lcm(const M& m, const N& n) {
        return std::lcm(m, n);
    }

    template <typename M, typename ...Rest>
    constexpr auto lcm(const M& first, const Rest&... rest) {
        return std::lcm(first, lcm(rest...));
    }
}

auto main() -> int {
    std::cout << math::lcm(3, 6, 12, 36) << std::endl;
    return 0;
}

See it in action here: https://wandbox.org/permlink/25jVinGytpvPaS4v

Ivaivah answered 25/11, 2017 at 17:10 Comment(0)
T
6

The algorithm isn't specific to C++. AFAIK, there's no standard library function.

To calculate the LCM, you first calculate the GCD (Greatest Common Divisor) using Euclids algorithm.

http://en.wikipedia.org/wiki/Greatest_common_divisor

The GCD algorithm is normally given for two parameters, but...

GCD (a, b, c) = GCD (a, GCD (b, c))
              = GCD (b, GCD (a, c))
              = GCD (c, GCD (a, b))
              = ...

To calculate the LCM, use...

                a * b
LCM (a, b) = ----------
             GCD (a, b)

The logic for that is based on prime factorization. The more general form (more than two variables) is...

                                          a                 b        
LCM (a, b, ...) = GCD (a, b, ...) * --------------- * --------------- * ...
                                    GCD (a, b, ...)   GCD (a, b, ...)

EDIT - actually, I think that last bit may be wrong. The first LCM (for two parameters) is right, though.

Tal answered 19/11, 2010 at 22:30 Comment(1)
gcd and lcm is a part of C++1z, though.Hustle
N
6

Using GCC with C++14 following code worked for me:

#include <algorithm>
#include <vector>

std::vector<int> v{4, 6, 10};    
auto lcm = std::accumulate(v.begin(), v.end(), 1, [](auto & a, auto & b) {
    return abs(a * b) / std::__gcd(a, b);
});

In C++17 there is std::lcm function (http://en.cppreference.com/w/cpp/numeric/lcm) that could be used in accumulate directly.

Numidia answered 16/12, 2016 at 13:37 Comment(0)
S
1

Not built in to the standard library. You need to either build it yourself or get a library that did it. I bet Boost has one...

Succession answered 19/11, 2010 at 22:17 Comment(0)
G
1

I just created gcd for multiple numbers:

#include <iostream>    
using namespace std;
int dbd(int n, int k, int y = 0);
int main()
{
    int h = 0, n, s;
    cin >> n;
    s = dbd(n, h);
    cout << s;
}

int dbd(int n, int k, int y){
        int d, x, h;
        cin >> x;
        while(x != y){
            if(y == 0){
                break;
            }
            if( x > y){
                x = x - y;
            }else{
                y = y - x;
            }
        }
        d = x;
        k++;
        if(k != n){
        d = dbd(n, k, x);
        }
    return d;
}

dbd - gcd.

n - number of numbers.

Ginnygino answered 1/12, 2012 at 17:55 Comment(1)
this algorithm is too inefficient. See Blastfurnace's versionComposer
S
0
/*

Copyright (c) 2011, Louis-Philippe Lessard
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

unsigned gcd ( unsigned a, unsigned b );
unsigned gcd_arr(unsigned * n, unsigned size);
unsigned lcm(unsigned a, unsigned b);
unsigned lcm_arr(unsigned * n, unsigned size);
int main()
{
    unsigned test1[] = {8, 9, 12, 13, 39, 7, 16, 24, 26, 15};
    unsigned test2[] = {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
    unsigned result;

    result = gcd_arr(test1, sizeof(test1) / sizeof(test1[0]));
    result = gcd_arr(test2, sizeof(test2) / sizeof(test2[0]));
    result = lcm_arr(test1, sizeof(test1) / sizeof(test1[0]));
    result = lcm_arr(test2, sizeof(test2) / sizeof(test2[0]));

    return result;
}


/**
* Find the greatest common divisor of 2 numbers
* See http://en.wikipedia.org/wiki/Greatest_common_divisor
*
* @param[in] a First number
* @param[in] b Second number
* @return greatest common divisor
*/
unsigned gcd ( unsigned a, unsigned b )
{
    unsigned c;
    while ( a != 0 )
    {
        c = a;
        a = b%a;
        b = c;
    }
    return b;
}

/**
* Find the least common multiple of 2 numbers
* See http://en.wikipedia.org/wiki/Least_common_multiple
*
* @param[in] a First number
* @param[in] b Second number
* @return least common multiple
*/
unsigned lcm(unsigned a, unsigned b)
{
    return (b / gcd(a, b) ) * a;
}

/**
* Find the greatest common divisor of an array of numbers
* See http://en.wikipedia.org/wiki/Greatest_common_divisor
*
* @param[in] n Pointer to an array of number
* @param[in] size Size of the array
* @return greatest common divisor
*/
unsigned gcd_arr(unsigned * n, unsigned size)
{
    unsigned last_gcd, i;
    if(size < 2) return 0;

    last_gcd = gcd(n[0], n[1]);

    for(i=2; i < size; i++)
    {
        last_gcd = gcd(last_gcd, n[i]);
    }

    return last_gcd;
}

/**
* Find the least common multiple of an array of numbers
* See http://en.wikipedia.org/wiki/Least_common_multiple
*
* @param[in] n Pointer to an array of number
* @param[in] size Size of the array
* @return least common multiple
*/
unsigned lcm_arr(unsigned * n, unsigned size)
{
    unsigned last_lcm, i;

    if(size < 2) return 0;

    last_lcm = lcm(n[0], n[1]);

    for(i=2; i < size; i++)
    {
        last_lcm = lcm(last_lcm, n[i]);
    }

    return last_lcm;
}

Source code reference

Surfboat answered 5/11, 2012 at 21:10 Comment(1)
The most complete answerSciolism
F
0

You can calculate LCM and or GCM in boost like this:

#include <boost/math/common_factor.hpp>
#include <algorithm>
#include <iterator>


int main()
{
    using std::cout;
    using std::endl;

    cout << "The GCD and LCM of 6 and 15 are "
     << boost::math::gcd(6, 15) << " and "
     << boost::math::lcm(6, 15) << ", respectively."
     << endl;

    cout << "The GCD and LCM of 8 and 9 are "
     << boost::math::static_gcd<8, 9>::value
     << " and "
     << boost::math::static_lcm<8, 9>::value
     << ", respectively." << endl;
}

(Example taken from http://www.boost.org/doc/libs/1_31_0/libs/math/doc/common_factor.html)

Fastigiate answered 31/10, 2013 at 23:48 Comment(0)
F
0

The Codes given above only discusses about evaluating LCM for multiple numbers however it is very likely to happen that while performing multiplications we may overflow integer limit for data type storage

*A Corner Case :- *

e.g. if while evaluating you reach situation such that if LCM_till_now=1000000000000000 next_number_in_list=99999999999999 and Hence GCD=1 (as both of them are relatively co-prime to each other)

So if u perform operation (LCM_till_now*next_number_in_list) will not even fit in "unsigned long long int"

Remedy :- 1.Use Big Integer Class 2.Or if the problem is asking for LCM%MOD----------->then apply properties of modular arithmetic.

Fairish answered 5/7, 2014 at 21:22 Comment(0)
P
0

I found this while searching a similar problem and wanted to contribute what I came up with for two numbers.

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    cin >> x >> y;

    // zero is not a common multiple so error out
    if (x * y == 0)
        return -1;

    int n = min(x, y);
    while (max(x, y) % n)
        n--;

    cout << n << endl;
}
Pass answered 30/9, 2014 at 2:26 Comment(2)
This solution is flawed. If x or y is 0 and the other one positive then the modulo operation will result in undefinied behaviour (see https://mcmap.net/q/295988/-can-39-t-mod-zero).Ampoule
Good catch. Fixed based on your comment.Pass
O
0

Using the fact that lcm should be divisible by all the numbers in list. Here the list is a vector containing numbers

        int lcm=*(len.begin());
    int ini=lcm;
    int val;
    int i=1;
    for(it=len.begin()+1;it!=len.end();it++)
    {
        val=*it;
        while(lcm%(val)!=0)
        {
            lcm+=ini;
        }
        ini=lcm;
    }
    printf("%llu\n",lcm);
    len.clear();
Oakland answered 14/11, 2015 at 9:36 Comment(0)
A
0
#include<iostream>
using namespace std;

int lcm(int, int, int); 

int main()
{
    int a, b, c, ans;
    cout<<"Enter the numbers to find its LCM"<<endl; //NOTE: LCM can be found only for non zero numbers. 
    cout<<"A = "; cin>>a;
    cout<<"B = "; cin>>b;
    cout<<"C = "; cin>>c; 
    ans = lcm(a,b,c);
    cout<<"LCM of A B and C is "<<ans;
}

int lcm(int a, int b, int c){
    static int i=1;

    if(i%a == 0 && i%b == 0 && i%c ==0){  //this can be altered according to the number of parameters required i.e this is for three inputs
        return i;
    } else {
        i++;
        lcm(a,b,c);
        return i;
    }
}
Antechamber answered 29/4, 2021 at 18:2 Comment(0)
B
-1

If you look at this page, you can see a fairly simple algorithm you could use. :-)

I'm not saying it's efficient or anything, mind, but it does conceptually scale to multiple numbers. You only need space for keeping track of your original numbers and a cloned set that you manipulate until you find the LCM.

Boykin answered 19/11, 2010 at 22:28 Comment(0)
K
-1
#include
#include

void main()
{
    clrscr();

    int x,y,gcd=1;

    cout<>x;

    cout<>y;

    for(int i=1;i<1000;++i)
    {
        if((x%i==0)&&(y%i==0))
        gcd=i;
    }

    cout<<"\n\n\nGCD :"<
    cout<<"\n\n\nLCM :"<<(x*y)/gcd;

    getch();
}
Kacikacie answered 6/2, 2011 at 3:24 Comment(0)
L
-1
  • let the set of numbers whose lcm you wish to calculate be theta
  • let i, the multiplier, be = 1
  • let x = the largest number in theta
  • x * i
  • if for every element j in theta, (x*i)%j=0 then x*i is the least LCM
  • if not, loop, and increment i by 1
Laocoon answered 1/10, 2013 at 6:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.