Partage
  • Partager sur Facebook
  • Partager sur Twitter

Racine carré et fraction irréductible

    11 février 2018 à 18:53:09

    Bonjour, je suis actuellement entrain de coder un programme résolvant automatiquement certaines équations. Cependant je voudrais avoir une valeur précise et non approchée. 

    Connaissez-vous un code me permettant ainsi de calculer une racine carré et  :  - dans les cas où cela donne un carré parfait prendre la valeur décimal ; - et dans celui où ça donne une valeur approchée prendre la racine carré ?

    J'ai le même problème pour les divisions.

    N'hésitez pas à me contacter si mon message n'est pas assez claire.

    Merci d'avance pour votre réponse. 

    -
    Edité par CorentinLeBomin 11 février 2018 à 18:53:42

    • Partager sur Facebook
    • Partager sur Twitter
      12 février 2018 à 13:54:23

      Quoi qu'il arrive, ta variable est stockée dans un float (ou double) non ? Ce n'est donc que lors de l'affichage que le problème survient :

      • Si l'on tombe sur un entier, on n'affiche pas les zéros
      • Sinon on affiche de manière normale.

      Pour ça tu peux utiliser les fonctions "ceils" et "floor" de <math.h> qui permettent respectivement d'arrondir au supérieur et d'arrondir à l'inférieur. Si l'un des deux arrondis est strictement égal à ta valeur, alors ils s'agit d'un nombre entier. Ca te donne qqchose comme ça :

      #include <stdlib.h>
      #include <stdio.h>
      #include <math.h>
      
      int main(int argc, char** argv) {
          double res;
      
          // Calcul de la racine ...
      
          if(ceil(res) == res || floor(res) == res) {
              printf("Res : %.lf\n", res);    // Le point n'est pas une faute de frappe, c'est ce qui permet de ne pas afficher les décimales.
          } else {
              printf("Res : %lf\n", res);
          }
      
          // Autres trucs ...
      
      }


      De même pour les fractions.

      NB : ceil et floor renvoient un double, si tu manipules des float, un cast sera peut-être nécessaire.

      -
      Edité par Insonore 12 février 2018 à 13:55:30

      • Partager sur Facebook
      • Partager sur Twitter
      Hugo
        12 février 2018 à 14:14:37

        Tu ne peux pas tester l’égalité sur des nombres flottants a cause des approximations. Il faut tester une plage de valeurs (-0.001/+0.001 par ex). ;)

        • Partager sur Facebook
        • Partager sur Twitter
          12 février 2018 à 14:18:54

          Au lieu de chercher lequel est mieux de ceil et floor, il y a round qui retourne l'entier le plus proche sous forme d'un flottant, et lrint d'un int.

          Faut lire les docs, les gars.

          http://www.cplusplus.com/reference/cmath/lrint/

          http://www.cplusplus.com/reference/cmath/round/

          -
          Edité par michelbillaud 12 février 2018 à 14:21:48

          • Partager sur Facebook
          • Partager sur Twitter
            12 février 2018 à 14:32:04

            Pouet_forever a écrit:

            Tu ne peux pas tester l’égalité sur des nombres flottants a cause des approximations. Il faut tester une plage de valeurs (-0.001/+0.001 par ex). ;)


            Même avec des long float c'est nécessaire :/ ? Je pensais que seul les float exigeaient cette vérif'

            michelbillaud a écrit:

            Au lieu de chercher lequel est mieux de ceil et floor, il y a round qui retourne l'entier le plus proche sous forme d'un flottant, et lrint d'un int.

            Je ne connaissais pas round.

            michelbillaud a écrit:

            Faut lire les docs, les gars.

            La condescendance par contre tu peux éviter.



            • Partager sur Facebook
            • Partager sur Twitter
            Hugo
              12 février 2018 à 15:10:44

              Oui, float, double et long double restent des nombres flottants a double précision (IEEE 754). ;)

              • Partager sur Facebook
              • Partager sur Twitter
                13 février 2018 à 8:42:14

                Insonore a écrit:

                Pouet_forever a écrit:

                Tu ne peux pas tester l’égalité sur des nombres flottants a cause des approximations. Il faut tester une plage de valeurs (-0.001/+0.001 par ex). ;)


                Même avec des long float c'est nécessaire :/ ? Je pensais que seul les float exigeaient cette vérif'

                michelbillaud a écrit:

                Au lieu de chercher lequel est mieux de ceil et floor, il y a round qui retourne l'entier le plus proche sous forme d'un flottant, et lrint d'un int.

                Je ne connaissais pas round.

                michelbillaud a écrit:

                Faut lire les docs, les gars.

                La condescendance par contre tu peux éviter.




                1. Quand on n'est pas trop content d'une fonction de bibliothèque, comme ceil ou floor, le réflexe minimal doit être de commencer par chercher dans la doc de ces fonctions, dans la section "voir aussi".  Parce que trouver l'entier le plus proche c'est un besoin courant, donc c'est certainement couvert par une fonction standard.

                2. quand je dis "il faut lire la doc", c'est ce que je fais moi-même, et c'est un encouragement à le faire, parce qu'on a généralement la flemme.

                3. et c'est à cette occasion qu'hier j'ai découvert cette fonction (et pourtant ça fait quelques décennies que je programme), parce que je souhaitais aider celui qui a posé la question. 

                4. Par contre, je ne crois pas que des réponses du type "faut peut être faire un cast" aident vraiment. C'est bien de vouloir aider, mais encore faut il essayer de donner des conseils qui tiennent la route

                5. Et la condescendance elle ne serait pas un peu dans l'oeil de ceux qui n'ont pas l'obligeance de faire un effort pour donner des informations exactes à  ceux qui en demandent ?

                -
                Edité par michelbillaud 13 février 2018 à 8:43:41

                • Partager sur Facebook
                • Partager sur Twitter
                  13 février 2018 à 10:07:40

                  michelbillaud a écrit:


                  1. Quand on n'est pas trop content d'une fonction de bibliothèque, ...


                  Sauf que je me contente très bien de ceil et de floor. Donc je n'ai pas cherché une alternative sur le coup.

                  michelbillaud a écrit:

                  2. quand je dis "il faut lire la doc", c'est ce que je fais moi-même, et c'est un encouragement à le faire, parce qu'on a généralement la flemme.

                  J'avais bien saisi qu'il s'agissait d'un encouragement. C'est le ton abordé qui me dérange, pas le propos.

                  michelbillaud a écrit:

                  4. Par contre, je ne crois pas que des réponses du type "faut peut être faire un cast" aident vraiment. C'est bien de vouloir aider, mais encore faut il essayer de donner des conseils qui tiennent la route

                  Prévenir d'une éventuelle modification à apporter aide, toujours. Mais oui le soucis est que je la qualifie "d'éventuelle". J'aurais du aller vérifier, pour fournir une réponse exacte, certes. Mais je préfère prévenir que d'affirmer qqchose de faux.

                  michelbillaud a écrit:

                  5. Et la condescendance elle ne serait pas un peu dans l'oeil de ceux qui n'ont pas l'obligeance de faire un effort pour donner des informations exactes à  ceux qui en demandent ?

                  Non, il n'y a rien de condescendant dans une réponse du moment qu'elle est respectueuse, qu'elle contienne une imprécision sur un détail de la réponse ou non.

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Hugo
                    13 février 2018 à 10:50:54

                    Pour revenir au sujet. On peut simplement montrer pourquoi il ne faut pas tester les nombres flottants avec un simple ==. 0.1 * 10 n'est pas égal a 0.1 + 0.1 ... + 0.1 qui n'est pas egal a var = 0.1 * 10. :

                     #include <stdio.h>
                    
                    int main(void) {
                    	float a = 0.1;
                    	float b = 0.0;
                    	float c = 0.0;
                    	int i;
                    
                    	for (i = 0; i < 10; i++)
                    		b += a;
                    
                    	c = a * 10.0;
                    	printf("      a = %.20f\n", a);
                    	printf("a * 10. = %.20f\n", a * 10.);
                    	printf("      b = %.20f\n", b);
                    	printf("      c = %.20f\n", c);
                    
                    	return 0;
                    }


                    Ce qui donne :

                          a = 0.10000000149011611938
                    a * 10. = 1.00000001490116119385
                          b = 1.00000011920928955078
                          c = 1.00000000000000000000


                    Pourtant les 3 calculs font la même chose ! ;)

                    • Partager sur Facebook
                    • Partager sur Twitter
                      13 février 2018 à 10:55:20

                      Insonore a écrit:

                      J'avais bien saisi qu'il s'agissait d'un encouragement. C'est le ton abordé qui me dérange, pas le propos.

                      Par écrit, il n'y a pas de ton, à part celui qu'on suppose à son interlocuteur. 

                      Qu'est-ce qui est dérangeant ? Qu'il faille lire la doc ? Que ça demande un effort ? Qu'il soit besoin de le dire et répéter ?

                      -
                      Edité par michelbillaud 13 février 2018 à 10:56:03

                      • Partager sur Facebook
                      • Partager sur Twitter
                        13 février 2018 à 11:39:27

                        Merci d’arrêter de polluer le fil et de continuer vos chamaillages en message prive...
                        • Partager sur Facebook
                        • Partager sur Twitter
                          13 février 2018 à 11:43:26

                          Salut,

                          Le souci pointé du doigt par Pouet est assez connu, au moins quand on y a été confonté une fois.

                          J'utilise ceci :

                          bool CEV_doubleIsEqual(double value1, double value2, double tolerance)
                          {/*retruns true if value1 is within (value2 +/- tolerence)*/
                              return ((value1 >= value2-tolerance) && (value1 <= value2+tolerance));
                          }

                          Il est intéressant de noter que c = 10*a donne le bon résultat, alors que a lui-même ne vaut pas exactement 0.1, d'ailleur 10*a ne vaut pas 1 non-plus...

                          Bonne continuation.

                          • Partager sur Facebook
                          • Partager sur Twitter

                          Bonhomme !! | Jeu de plateforme : Prototype.

                            13 février 2018 à 13:15:47

                            La formulation habituelle, c'est d'utiliser la fonction prédéfinie qui exprime la valeur absolue, ou une de ses copines (*)

                                 double fabs  (double x);
                                  float fabsf (float x);
                            long double fabsl (long double x);

                            dans du code du genre

                            return fabs(value1 - value2) <= tolerance;


                            ce qui est plus facile à écrire, et plus proche de la formulation mathématique habituelle.

                            Pendant qu'on y est, toujours penser qu'on ne fait pas n'importe quoi avec les nombres en virgule flottante. Si on ne fait pas gaffe, en additionnant n'importe comment, on se retrouve avec une série harmonique https://fr.wikipedia.org/wiki/S%C3%A9rie_harmonique qui a l'air de converger, alors que non

                            double harmo(int n) {
                               double s = 0;
                               for (int i = 1; i <= n; i++) {
                                  s +=  1.0/i;                    // ça bugge
                               }
                               return s;
                            }



                            (*) qu'on trouve dans la doc  http://www.cplusplus.com/reference/cmath/fabs/ je dis ça, je dis rien, je ne voudrais pas avoir l'air d'insister lourdement.

                            -
                            Edité par michelbillaud 13 février 2018 à 13:20:54

                            • Partager sur Facebook
                            • Partager sur Twitter
                              13 février 2018 à 13:42:22

                              michelbillaud a écrit:

                              return fabs(value1 - value2) <= tolerance;

                              Justement non, la methode de `drx` est mieux. Pour des valeurs de value1/2 grandes ou petites tu risques d'avoir des soucis. On pourrait meme ajouter qu'on pourrait prendre les constantes `FLT_EPSILON`, `DBL_EPSILON` et `LDBL_EPSILON` pour la tolerence. :)

                              • Partager sur Facebook
                              • Partager sur Twitter
                                13 février 2018 à 13:56:26

                                allons bon, et quels soucis ?

                                FLT_EPSILON, c'est la difference entre 1 et le plus petit nombre normalisé > à 1. C'est bien beau de l'agiter dans la conversation, mais tu comptes t'en servir comment pour comparer deux nombres à epsilon près ?

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  13 février 2018 à 14:12:55

                                  Je suis intéressé par le sujet mais le lien que tu donnes est trop long. Il n'y a pas de réponse plus courte ? Je l'ai quand même survolé, et j'aime bien la dernière fonction (qui calcule une sorte d'erreur relative). Je crois que c'est celle que j'adopterais.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    13 février 2018 à 14:57:58

                                    Autrement dit, on renvoie sur une douzaine de réponses (à d'autres problèmes) sur stackoverflow, faute de pouvoir dire quels problèmes fabs(v1-v1)<eps   pose par rapport à ((v1 >= v-eps) && (v1 <= v2+eps));   ni ce que vient faire FLT_EPSILON là dedans :-)

                                    Quand on cherche une valeur approchée, rien à y faire, il faut indiquer l'erreur absolue ou relative que l'on tolère. Si elle se calculait toute seule...

                                    D'ailleurs, c'est dans les réponses

                                    Q: How does one calculate tol correctly for all general cases? 
                                    
                                    A: One doesn't. This kind of comparison is not suitable for all cases, regardless of tolerance value (and FWIW, wouldn't you know best what the appropriate tolerance is for the thing you are testing?)



                                    Pour en revenir à la question d'origine, l'impression que ça donne quand même, c'est que le demandeur voudrait des valeurs exactes.

                                    Autant l'arrêter tout de suite :  c'est rigoureusement impossible avec des nombres en virgule flottante.  Et pas la peine d'aller chercher des nombres compliqués : 1/3, 1/5, 1/7, .... ça ne se représente que de façon approchée.

                                    -
                                    Edité par michelbillaud 13 février 2018 à 15:03:46

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      13 février 2018 à 15:34:10

                                      Je pensais plutôt au lien proposé dans la première réponse ! :) https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

                                      Apres, oui, il faut indiquer l'erreur, c'est pour ça que ça s'appelle la tolérance ! :p Mais j'admets que je ne suis pas assez calé sur les nombres flottants, c'est pour ça que j'ai préféré donner un lien plutôt que raconter des conneries. ;)

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        13 février 2018 à 15:54:54

                                        Re,

                                        De toute façon, quand on va vraiment loin, les 2 fonctions échouent :

                                        bool FABS_doubleIsEqual(double val1, double val2, double tol)
                                        {
                                            return fabs(val1-val2) <= tol;
                                        }
                                        
                                        bool CEV_doubleIsEqual(double value1, double value2, double tolerance)
                                        {/*retruns true if value1 is within (value2 +/- tolerence)*/
                                            return ((value1 >= value2-tolerance) && (value1 <= value2+tolerance));
                                        }
                                        
                                        int main(void)
                                        {
                                            double val1 = 0.000035644337567, 
                                                   val2 = val1 + 0.000000000000001;
                                        
                                            printf("fabs says %s\n", FABS_doubleIsEqual(val1, val2, 0.000000000000001)? "true" : "false");
                                            printf("cev says %s\n", CEV_doubleIsEqual(val1, val2, 0.000000000000001)? "true" : "false");
                                        
                                            return 0;
                                        }
                                        fabs says false
                                        cev says false

                                        Je pense qu'il y a un moyen plus fiable (mais plus lourd) en extrayant exposant et mantisse et en les comparants dans leurs coins.

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Bonhomme !! | Jeu de plateforme : Prototype.

                                          13 février 2018 à 16:11:54

                                          Pas forcement ! :D

                                          fabs says false
                                          cev says true
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            13 février 2018 à 16:20:44

                                            drx a écrit:

                                            Je pense qu'il y a un moyen plus fiable (mais plus lourd) en extrayant exposant et mantisse et en les comparants dans leurs coins.

                                            S'il faut extraire les mantisses à chaque comparaison impliquant un flottant, on n'est pas sortis de l'auberge. Reste à savoir si  @CorentinLeBomin cherches à avoir un résultat parfait, ou est-ce qu'une approximation suffit.

                                            -
                                            Edité par Insonore 13 février 2018 à 16:21:04

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Hugo
                                              13 février 2018 à 17:14:37

                                              Re,

                                              Bin, après tout dépend des gammes de valeur dans lesquelles on travaillle. Perso, je demande rarement plus que le millième et je compare à 2 près, parce que ça va bien pour ce que j'en ai à faire.

                                              Les extractions / comparaison ne me semblent pas si coûteuse que ça, 2 filtres et 2 compraisons, les règles de continuités sur un flottant sont les mêmes que pour un entier (séparemment pour exposant et mantisse, bien entendu), si le binaire est plus grand, la valeur est plus grande et vice versa.

                                              Je vais m'atteller à avoir le résultat attendu sur les fonctions qu'on a avec la tolérence pour voir. Mais pas tout de suite, quand je serai rentré...

                                              • Partager sur Facebook
                                              • Partager sur Twitter

                                              Bonhomme !! | Jeu de plateforme : Prototype.

                                                13 février 2018 à 18:32:04

                                                Evidemment que ça échoue. Il y a 52/53 bits pour la mantisse, faut pas compter sur le 54ieme.

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  13 février 2018 à 23:21:12

                                                  Re,

                                                  J'ai bossé un peu le truc... Je n'ai pas fini de fignoler, mais ma conclusion (perso, hein, rien d'absolu) est qu'il faudrait personnaliser le jeu de fonctions selon les gammes de valeurs dans lesquelles on veut travailler. Pas de fonction "générique" qui puisse tenir la route par tout temps, selon moi.

                                                  Egalement, j'ai essayé de revoir la notion de "tolérence". Plutôt que de la considérer comme une valeur de la gamme, la considérer comme un nombre de bits significatifs, mais c'est encore un peu boîteux... Et pas facile de se faire une idée de ce que ça peut représenter comme écart aux valeurs.

                                                  Il est clair qu'il ne faut pas mélanger grands et petits nombres, les erreurs deviennent vite monumentales...En combinant grand nombre et précision, on a vite une erreur de plus d'un dixième rien que sur l'attribution de la constante à une variable, voire 1 ou plus sur de plus grandes valeurs.

                                                  En double précision, 35446544123736670.324 va être stocké comme 35446544123736672, un peu moins de 1.7 d'erreur, ce qui est vite assez grave, surtout si on croit à l'utilité du millième... On va presque avoir un meilleur résultat en travaillant sur des entiers puisqu'on va ne perdre que les 0.324

                                                  Mais je dit une évidence pour certains, juste que je n'avais jamais vraiment essayé de stresser les flottants. C'est pluôt intéressant.

                                                  Bonne continuation.

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Bonhomme !! | Jeu de plateforme : Prototype.

                                                    14 février 2018 à 8:12:31

                                                    Salut, déjà, si vous voulez évaluer un résultat parfait au sens mathématique du terme , n'utilisez pas float ou double, par définition, ils sont inexacts.

                                                    Essayez de poser a = 0.5 * 3 par exemple et essayez de voir si a == 0.3 .... Pour voir.

                                                    Je pense que pour son problème il faut garder u e classe ou structure fraction ou racine qui contiendront des nombres entiers, et quand on veut la division on calcule un PGCD. Et si le PGCD vaut le dénominateur, alors on procede a la division entière , sinon on peut simplifier la fraction. 

                                                    Pour la racines pareil, il existe des méthodes pour simplifier les racines, et si ça va jusqu'au bout alors c'est une racine exacte.

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter

                                                    Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                      20 février 2018 à 22:15:05

                                                      Merci beaucoup pour toutes vos réponses. Je vais effectivement essayer de travailler avec un arrondie au millième, ou au centième dans certains cas, cela devrait me suffire à obtenir des résultats toujours exploitables.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter

                                                      Racine carré et fraction irréductible

                                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                      • Editeur
                                                      • Markdown