Plus petit commun multiple avec doubles en C

Je fais un travail pour un cours Coursera qui me demande de calculer le plus petit commun multiple de deux nombres, dont l’un ne dépasse pas 2 * 10 ^ 9. J’écris ceci en C et mon code est exécuté un cas de test avec les numéros 226553150 et 1023473145. La réponse est 46374212988031350, mais je reçois 46374212988031344, qui est par 6!

J’ai écrit une solution correcte en Python qui utilise essentiellement la même approche que celle que j’ai publiée ci-dessous, mais les détails de précision numérique sont évidemment pris en charge pour moi. Je poste ceci sur SO pour en apprendre davantage sur la précision en virgule flottante en C, et parce que la plupart des questions que j’ai vues sur Internet et SO concernant LCM ne traitent que des entiers.

Voici mon code, que je comstack avec gcc -pipe -O2 -std=c11 lcm.c :

 #include  #include  double gcd(double a, double b) { if (b == 0) { return a; } return gcd(b, fmod(a,b)); } double lcm(double a, double b) { return (a * b) / gcd(a,b); } int main() { double a; double b; scanf("%lf %lf", &a, &b); printf("%.0lf\n", lcm(a,b)); return 0; } 

    Le nombre le plus proche de 46374212988031350 pouvant être représenté par un double est 46374212988031352 (désactivé par 2 ). Vous pouvez tester cela en utilisant le calcul le plus simple.

     #include  int main() { // The gcd of 226553150 and 1023473145 is 5 double a = 226553150; double b = 1023473145; double c = b/5; double lcm = a*c; printf("lcm: %.0lf\n", lcm); return 0; } 

    Sortie:

     lcm: 46374212988031352 

    Vous aggravez la situation en calculant (a * b)/gcd(a, b) . Le nombre le plus proche de 231871064940156750 , (a*b) , pouvant être représenté par un nombre à virgule flottante est 231871064940156736 . En d’autres termes, vous perdez plus de précision en calculant d’abord (a*b) .

    Vous n’avez pas posté le code Python que vous avez utilisé pour faire le même calcul. Je suppose que Python utilise des types intégraux pour les nombres. Si j’utilise:

     a = 226553150; b = 1023473145; c = b/5; lcm = a*c print("lcm:", lcm) 

    Je reçois la sortie:

     ('lcm:', 46374212988031350) 

    Cependant, si j’utilise des littéraux à virgule flottante pour a et b , j’obtiens une sortie différente:

     a = 226553150.0; b = 1023473145.0; c = b/5; lcm = a*c print("lcm:", "%18.0lf" % lcm) 

    Sortie:

     ('lcm:', ' 46374212988031352') 

    En résumé, la différence que vous voyez entre les programmes C et Python est due à l’utilisation de types à virgule flottante par rapport à des types intégraux. Si vous utilisez long ou long long au lieu de double , vous devriez obtenir le même résultat que le programme Python, comme indiqué dans la réponse de Deng Haijun .

    Je doute que vous utilisiez float pas longtemps. Je change float en long comme suit, alors ça marche bien.

     #include  #include  long gcd(long a, long b) { if (b == 0) { return a; } return gcd(b, a%b); } long lcm(long a, long b) { return (a * b) / gcd(a,b); } int main() { long a; long b; scanf("%ld %ld", &a, &b); printf("%ld\n", lcm(a,b)); return 0; }