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
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.
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
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.
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
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...
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;
}
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.
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 ?
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.
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
Apres, oui, il faut indiquer l'erreur, c'est pour ça que ça s'appelle la tolérance ! 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.
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.
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é...
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.
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.
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.
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.
Bonhomme !! | Jeu de plateforme : Prototype.
Bonhomme !! | Jeu de plateforme : Prototype.
Bonhomme !! | Jeu de plateforme : Prototype.
Bonhomme !! | Jeu de plateforme : Prototype.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html