web-dev-qa-db-fra.com

Algorithme C++ pour calculer le plus petit commun multiple pour plusieurs nombres

Existe-t-il un algorithme C++ pour calculer le plus petit commun multiple pour plusieurs nombres, comme lcm(3,6,12) ou lcm(5,7,9,12)?

24
Askener

Vous pouvez utiliser std :: accumulate et quelques fonctions auxiliaires:

#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';
}
45
Blastfurnace

boost fournit des fonctions pour le calcul lcm de 2 nombres (voir ici )

Puis en utilisant le fait que

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

Vous pouvez aussi facilement calculer lcm pour plusieurs nombres

17
Vladimir

L'algorithme n'est pas spécifique à C++. Autant que je sache, il n'y a pas de fonction de bibliothèque standard.

Pour calculer le LCM, vous devez d'abord calculer le GCD (le plus grand commun diviseur) à l'aide de l'algorithme d'Euclids.

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

L'algorithme GCD est normalement donné pour deux paramètres, mais ...

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

Pour calculer le LCM, utilisez ...

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

La logique pour cela est basée sur la factorisation première. La forme plus générale (plus de deux variables) est ...

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

EDIT - en fait, je pense que ce dernier point peut être faux. Le premier LCM (pour deux paramètres) est correct, cependant.

6
Steve314

Utiliser GCC avec le code C++ 14 suivant a fonctionné pour moi:

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

En C++ 17, il existe une fonction std :: lcm ( http://en.cppreference.com/w/cpp/numeric/lcm ) qui peut être utilisée directement dans accumulate.

4
dividedbyzero

A partir de C++ 17, vous pouvez utiliser std::lcm .

Et voici un petit programme qui montre comment se spécialiser pour plusieurs paramètres

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

Testez-le ici: https://wandbox.org/permlink/25jVinGytpvPaS4v

3
smac89

Je viens de créer gcd pour plusieurs numéros:

#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 - nombre de nombres.

1
TheHaris

Non intégré à la bibliothèque standard. Vous devez le construire vous-même ou vous procurer une bibliothèque qui l’a fait. Je parie que Boost en a un ... 

1
John Dibling

En utilisant le fait que lcm devrait être divisible par tous les nombres de la liste. Ici la liste est un vecteur contenant des nombres 

        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();
0
Archit Kansal

J'ai trouvé cela en cherchant un problème similaire et je voulais contribuer à ce que j'ai proposé pour deux nombres.

#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;
}
0
Chuck Claunch

Les codes donnés ci-dessus ne traitent que de l’évaluation du LCM pour plusieurs numéros, mais il est très probable que lors de la multiplication, nous pouvons déborder nombre maximal pour le stockage du type de données

* Un coin affaire: - *

par exemple. si, lors de l'évaluation, vous atteignez une situation telle que si LCM_till_now = 1000000000000000 next_number_in_list = 99999999999999 et, par conséquent, GCD = 1 (car les deux sont relativement co-prime l'un par rapport à l'autre)

Donc, si vous effectuez l'opération (LCM_till_now * next_number_in_list) ne rentrera même pas dans "unsigned long long int" 

Solution: - 1.Utilisez la classe de grand entier 2.Ou si le problème demande LCM% MOD ----------->, appliquez les propriétés de l'arithmétique modulaire.

0
user3166642
/*

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

Référence du code source

0
yayay

Vous pouvez calculer LCM et/ou GCM en boost comme ceci:

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

(Exemple tiré de http://www.boost.org/doc/libs/1_31_0/libs/math/doc/common_factor.html )

0
portforwardpodcast