Problème avec math.h [résolu et amélioré !!] - C - Programmation
Marsh Posté le 31-12-2006 à 19:10:56
D'apres la page man (http://www.linux-kheops.com/doc/man/manfr/man-html-0.9/man3/floor.3.html) il faut aussi inclure la librairie de math a la compiltation/edition des liens -lm en ligne de commande
Y as tu pensé?
Marsh Posté le 31-12-2006 à 19:18:59
non !! je teste !!
edit : je crois que ça marche !!!
Marsh Posté le 01-01-2007 à 00:30:17
nicodu95 a écrit : |
Inclure un header te permet juste d'avoir le prototype des fonctions. Le code exécutable des fonctions, lui, se trouve dans les diverses librairies. En général il se trouve dans la librairie standard "/usr/lib/libc.a" qui est automatiquement liée mais s'il se trouve dans une autre librairie, par exemple "/usr/lib/libm.a" c'est à toi de demander à relier la librairie en question lors de la compilation
cc prog.c /usr/lib/libm.a -o prog
Le raccourci "-lxxx" est un alias vers "/usr/lib/libxxx.a" donc -lm <=> /usr/lib/libm.a
Marsh Posté le 01-01-2007 à 14:24:36
merci pour votre aide rapide et bonne année !!!
mais pourquoi je n'est pas à faire ça pour stdio.h ??
Marsh Posté le 01-01-2007 à 14:39:42
nicodu95 a écrit : merci pour votre aide rapide et bonne année !!! |
La bibliothèque standard du C est une collection de fonctions. Le langage C ne précise pas comment doit êre implémentée cette bibliothèque.
Néanmoins, le plus souvent, les fonctions de <math.h> sont séparées des autres, probablement parce qu'elles représentent un 'poids' important, qui pourrait surcharger inutilement une application qui n'utiliserait pas ces fonctions.
Donc, toutes les fonctions, sauf mathématiques, sont dans une bibliothèque C 'de base' qui est automatiquement liée à l'application, et, si besoin est, on ajoute (à la main : par exemple -lm) la bibliothèque mathématique.
Marsh Posté le 01-01-2007 à 16:12:40
nicodu95 a écrit : je comprend pas parce que j'inclue bien math.h , partout sur le web j'ai lu qu'il fallait l'inclure pour ce servir de floor. |
Surtout que "floor" n'est franchement pas utile pour trouver un nombre premier. Arrondir une division en virgule flottante puis regarder si le résultat arrondi est égal au résultat brut pour savoir si la division peut se faire... Autant regarder directement si le reste de la division (qu'on récupère avec l'opérateur modulo %) vaut 0 !!!
Par ailleurs, j'ai un sérieux doute sur la réussite globale de ton algo. En ligne 27, il y a une division de x (int) par t[i] (int). La division se fera donc intégralement dans le type le plus "large" présent ici, c.a.d. "int" et le résultat, forcément "int" sera placé dans "q".
C'est comme si t'écrivais "double q=20 / 7" => Tu auras "q" = 2.0000" alors que t'espères très certainement "q=2,857"...
De toute façon, un nombre premier étant un nombre indivisible, il n'y a aucune division à faire en virgule flottante donc les types "double" sont totalement inutiles.
Enfin ton algo pourrait être sèrieusement optimisé. En effet, en ligne 22 tu fais une boucle de 0 à l pour diviser ton nombre testé par tous les nombres premiers déjà calculés ce qui est totalement inutile. En effet, si tu trouves un nombre "m" tel que "x / m = n" avec "m > n" cela signifie que tu auras forcément trouvé "n" bien avant "m" puisque t'auras en équivalence "x / n = m"...
Donc tu peux sans soucis arrêter ta boucle dès que "fq" devient plus petit que "t[i]"... Il existe même un algo (crible d'Erastothène) où on n'a aucune division à faire et il serait parfaitement adapté à ton cas puisque cet algo barre dans une liste de nombre (ton tableau "t" ) tous les nombres non-premiers par simple balayage du tableau...
De plus, que représente "t" ? Pour moi cela devrait être l'ensemble des nombres premiers déjà trouvés (enfin cela me parait logique car s'il fallait se baser sur tes commentaires pour comprendre ton algo...). Or, tu places "x" dans "t[...]" dès que t'as trouvé un résultat où la division réussit... donc au final t'auras dans le tableau "t" l'ensemble des nombres non-premiers. Quoique ça marche aussi puisqu'en affichant tous les nombres qui ne sont pas dans "t" tu n'auras que des nombres premiers...
Pas mal de choses à revoir...
Marsh Posté le 01-01-2007 à 19:47:11
oui je sais le code qui est la ne marche pas par contre celui la marche :
Code :
|
je sais déja faire du php et du java mais ça fais 2 jours que j'essaye le C à travers cette algo
par contre tes idées d'opti m'intéressent et c'est justement une "adaptation" du crible d'érasthotène
Marsh Posté le 01-01-2007 à 22:18:54
nicodu95 a écrit : oui je sais le code qui est la ne marche pas par contre celui la marche :
|
Heureusement que Taz ne passe plus sur le topic C
Rarement vu un code aussi "pur"... et ces "goto" qui sont... superbes !!!
Par ailleurs ca m'étonnerait beaucoup que l'instruction "x++" fonctionne avec "x" de type double. D'ailleurs c'est réellemement une super idée que d'avoir tout mis en double juste pour un simple problème de division. Et enfin c'est encore plus super de travailler en double alors qu'un nombre premier se calcule à partir d'une division entière réussie ou pas => autrement dit les double sont totalement inutiles.
nicodu95 a écrit : par contre tes idées d'opti m'intéressent et c'est justement une "adaptation" du crible d'érasthotène |
Une "adaptation personnalisée" alors... car le crible d'Erasthotène ne fait aucune division alors que toi t'arrêtes pas d'en faire !!!
Crible d'Erasthotène: Tu commences par initialiser tout ton tableau "t" à 0 signifiant "inconnu". Puis tu mets t[0] et t[1] à "-1" signifiant "pas premiers".
Puis tu pars de "2" et tu recherches la première valeur de ton tableau à "0" (donc ici c'est t[2]) que tu mets à "1" car premier. Puis tu prends tous les multiples de "2" (t[4], t[6], t[8] etc)... jusqu'à la fin et tu les flagues à "-1" (pas premiers).
Puis tu continues à chercher la valeur suivante de ton tableau à "0" (t'arrives donc à t[3]) que tu mets à "1" car premier et tous ses multiples (t[6], t[9] etc) à "-1" car non premiers. Puis tu cherches la valeur suivante à "0" qui est t[5] (car t[4] a été flagué à "-1" lors du traitement de t[2]) et tous les multiples (t[10], t[15], etc...) à "-1" puis la valeur suivante (t[7]) et etc...
Dès que t'es arrivé à "l", toutes les valeurs de ton tableau à "1" sont premières !!!
Marsh Posté le 01-01-2007 à 23:28:09
merci pour tes conseils ça fais deux jours que je "fais" du C
je vais regarder ça demain
merci
PS : c'est vrai qu'en faisons que des multiplication ça vas être plus rapide
Marsh Posté le 02-01-2007 à 13:56:26
nicodu95 a écrit : ça fais deux jours que je "fais" du C |
BIENVENUE DANS LE MONDE MAGIQUE !!!
nicodu95 a écrit : c'est vrai qu'en faisons que des multiplication ça vas être plus rapide |
Disons qu'en conservant les valeurs déjà calculées, c'est effectivement plus rapide.
Pour savoir si un nombre est premier, pas de secret. Tu le divises jusqu'à ce que le résultat soit plus petit que le diviseur. Si t'as trouvé aucune division exacte, alors il est premier.
En revanche, pour calculer tous les nombres premiers d'une liste, ben tu pars du premier de la liste et tu barres tous ses multiples puis tu va sur le second etc. Ce sera hyper plus rapide que de diviser chaque nombre par l'ensemble de ses diviseurs...
Marsh Posté le 02-01-2007 à 19:49:34
voila , et ça marche :
Code :
|
Par contre , si je demande les nombres premiers jusqu'à 1000, il m'affiche 999 et pour 100, 99
je pense que c'est à la ligne 20 :
Code :
|
mais je sais pas par quoi le remplacer , si c'est ça
edit : et c'est effectivement beaucoup plus rapide que le premier, merci Sve@r
edit2 : je peux rien calculer à partir de 2095000 (au miller près) ,au dessus , j'ai le droit à ça :
Citation : Program received signal SIGSEGV, Segmentation fault. |
dans GDB, sans GDB j'ai : "erreur de segmentation" et bien sur le programme ne s'exécute pas
Marsh Posté le 02-01-2007 à 19:59:54
nicodu95 a écrit :
mais je sais pas par quoi le remplacer , si c'est ça |
et si je demande les nombres premiers jusqu'à 12 884 901 888, il se passe quoi ?
Marsh Posté le 03-01-2007 à 07:11:10
nicodu95 a écrit :
|
Fais donc démarrer ta boucle d'initialisation à "2" puisque tu t'occupes ensuite de "0" et "1"...
nicodu95 a écrit : Par contre , si je demande les nombres premiers jusqu'à 1000, il m'affiche 999 et pour 100, 99
mais je sais pas par quoi le remplacer , si c'est ça |
Ben oui - Pour "l=100" et "i=3", tu fais "for (j=3; j < 33 (division entière de 100 / 3); j++)" donc il ne passera pas par l'étape "j=33" puisqu'il s'arrête à 32 donc tu ne taperas pas dans "t[99]"
Tu peux remplacer par "j<= l/i"... mais faudra faire gaffe au cas où "i*j == l" car là, tu dépasseras ton espace alloué quand tu taperas dans "t[i * j]" (le tableau va de t[0] jusqu'à t[l - 1]).
De plus, tu auras à chaque tour de boucle
- une division "l/i
- une multiplication "i * j"
tu peux éviter TOUS CES PROBLEMES d'un seul coup par:
Code :
|
Remarque: tu m'as fait réaliser que, effectivement, on pouvait faire partir le multiple à "i * i" alors que, au départ, j'ai cru que l'algo était faux car moi je l'aurais fait partir à "i * 2" (c'est d'ailleurs ce que j'ai dit dans mon post précédent). Mais quand on y réfléchit 2 mn, on comprend facilement que tous les multiples entre "i" et "i * i" sont déjà flagués par les multiples des premiers inférieurs à "i"
nicodu95 a écrit : edit2 : je peux rien calculer à partir de 2095000 (au miller près) ,au dessus , j'ai le droit à ça :[quote]Program received signal SIGSEGV, Segmentation fault. |
Ben t'es limité déjà par la valeur maximale du "int" signé (tu peux remplacer par "unsigned long" ou même "unsigned long long" si ton compilo accepte)... mais surtout faut bien penser que ton tableau "t[l]" est alloué dans la pile. Tu crois que la pile est si énorme que ça ???
Tu peux essayer de mettre ton tableau "t" en "static" ce qui le place dans une zone plus grande que la pile mais le mieux est de le remplacer par un pointeur pointant vers une zone mémoire allouée par malloc => tu remplaces "int t[l]" par "int *t" puis tu écrits en dessous "t=malloc(l * sizeof(int))". Il est bien à ce moment là de vérifier que "t" ne vaut pas NULL car sinon ça veut dire que le malloc a échoué donc c'est pas la peine de continuer. Et à la fin du code tu écris "free(t)".
Harkonnen a écrit : et si je demande les nombres premiers jusqu'à 12 884 901 888, il se passe quoi ? |
Rhaaa soit indulgent ... ça fait 2 jours qu'il fait du C - Il a réussi son algo et c'est tout ce qui compte...
Marsh Posté le 03-01-2007 à 10:51:45
Sve@r a écrit : |
ben chuis indulgent, mais bon, c'est bien beau d'utiliser scanf() pour une entrée (ce qui est une erreur, fgets() rulaize), mais faudrait voir aussi à valider cette entrée
Marsh Posté le 03-01-2007 à 11:42:06
Harkonnen a écrit : ben chuis indulgent, mais bon, c'est bien beau d'utiliser scanf() pour une entrée ce qui est une erreur |
Là faut accuser tous les bouquins de C. Tous parlent de "scanf" comme le moyen de faire saisir qqchose (zut je galère et j'arrive pas à trouver ce smiley !!!)
Harkonnen a écrit : mais faudrait voir aussi à valider cette entrée |
Citation : - je ne peux rien lui apprendre, il est trop impatient |
Star Wars V - L'empire contre-attaque
Marsh Posté le 03-01-2007 à 12:04:50
Citation :
|
il se passe rien , de même pour 2^32
sinon j'ai remplacer j<l/i par i*j<l que j'ai trouvé pendant la nuit
sinon ça marche impec maintenant avec tes modifs sve@r merci
Citation : Là faut accuser tous les bouquins de C. Tous parlent de "scanf" comme le moyen de faire saisir qqchose |
ouais et pas que les bouquins , même sur les tutos sur le web on vois ça .
ah aussi à la compil' il me mais un warning pour malloc :
Citation : nbprm2.c:10: warning: incompatible implicit declaration of built-in function %u2018malloc%u2019 |
et apropos de scanf c'est quoi le danger ??
merci à tous pour votre aide
Marsh Posté le 03-01-2007 à 12:19:01
nicodu95 a écrit : ah aussi à la compil' il me mais un warning pour malloc |
Si tu te documentes pas un peu sur les fonctions que t'utilises (man malloc) t'auras le même problème pour toute fonction qui n'est pas de type "int" pour lequel tu n'as pas mis son "#include" qui va bien...
Quand le compilo arrive sur une fonction inconnue (malloc, fopen, etc) il la met de type "int" par défaut. Puis il y a l'édition de liens avec la lib C (là où malloc est codé) et comme malloc n'est pas "int" => warning: incompatible implicit declaration of built-in function
Solution 1: prototyper toutes les fonctions que t'utilises comme il faut
Solution 2: inclure le header donné au début du man dans lequel la fonction en question a été prototypée par son créateur (je crois que pour malloc c'est <stdlib.h> )
nicodu95 a écrit : et apropos de scanf c'est quoi le danger ?? |
Exécute le truc suivant
#include <stdio.h> |
Ca m'étonnerait que le programme attende que tu aies saisi ton nom pour t'afficher le dernier "printf". Cependant rajoute un simple "getchar()" juste après la saisie de l'âge et ça fonctionnera.
Pour plus de détails, voir http://forum.hardware.fr/hfr/Progr [...] 9666_1.htm => Lis le topic en entier et attarde-toi sur le post de Emmanuel Delahaye du 28/12 à 00h45 et sur mon post du 28/12 à 11h10...
nicodu95 a écrit : ouais et pas que les bouquins , même sur les tutos sur le web on vois ça . |
<philosophie>C'est le problème de tout apprentissage: L'esprit humain ne peut pas progresser autrement qu'en détruisant en partie ce qui a été fait avant. Cela n'est pas seulement vrai pour l'Humanité dans son histoire, c'est aussi vrai pour tout individu. Comment comprendre que c'est la Terre qui tourne autour du Soleil si on n'a pas d'abord vu le Soleil en mouvement autour de la Terre ? Même si l'idée première qu'on se fait de cette vision est fausse, elle servira ensuite à comprendre plus facilement la réalité.
C'est en étudiant les théories (fausses) d'Aristote sur les 5 éléments et leur position immuable (la pierre composée uniquement de terre tend à rejoindre la terre et coule tandis que le bois composé en partie d'air tend en partie à rejoindre l'air et peut donc flotter) qu'Archimède a pu découvrir le principe de la flottabilité...</philosophie>
C'est pareil pour l'apprentissage du C. Il est nécessaire pour les premiers TP d'avoir une fonction de saisie et une fonction d'affichage, et la saisie doit prendre en compte le type de la variable saisie d'où la première fonction qu'on apprend qui est "scanf()". Puis, plus tard, une fois qu'on commence à être habitué au C et à ses impératifs, on revient sur "scanf()" et on explique qu'en fait, ce n'est pas du tout conseillé. Mais à ce niveau là, le débutant connait maintenant "fgets()" et "sscanf()" et sait s'en servir et peut comprendre en quoi "scanf()" n'est pas vraiment tiptop...
Marsh Posté le 03-01-2007 à 15:16:35
nicodu95 a écrit : |
sans blague ?
allez, maintenant tu as 15 mn pour expliquer pourquoi, je releve la copie à 15:30
Marsh Posté le 03-01-2007 à 15:18:22
nicodu95 a écrit : |
aucun controle de dépassement du buffer
Marsh Posté le 03-01-2007 à 16:00:17
Harkonnen a écrit : aucun controle de dépassement du buffer |
si mal utilisé, ce qui est le cas dans 99% de cas...
Marsh Posté le 03-01-2007 à 21:25:25
Sve@r a écrit : |
Je crois bien qu'aucune philosophication d'aucune sorte n'éclipsera le fait qu'une bonne partie de la bibliothèque C est mal foutue, voire inutilisable.
Marsh Posté le 03-01-2007 à 21:42:07
++fab a écrit : Je crois bien qu'aucune philosophication d'aucune sorte n'éclipsera le fait qu'une bonne partie de la bibliothèque C est mal foutue, voire inutilisable. |
Ah ??? Certains vont être très intéressés par un développement plus argumenté de cette affirmation...
"Mal foutue" c'est encore possible car la lib a été créée aux alentours de 1970 par tatonnements successifs... mais inutilisable ???
Marsh Posté le 03-01-2007 à 22:09:44
Sve@r a écrit : Ah ??? Certains vont être très intéressés par un développement plus argumenté de cette affirmation... |
Ah. Et bien laisse les autres parler -- et mon affirmation commence par "Je crois".
Sve@r a écrit : "Mal foutue" c'est encore possible car la lib a été créée aux alentours de 1970 par tatonnements successifs... mais inutilisable ??? |
Appelle un chat un chat. S'il ne faut pas utiliser une fonction (comme tu le dis de scanf), c'est qu'elle est mal foutue.
Inutilisable, c'est ce qui est décrété à propos de certaines fonctions de la bibliothèque C, sur certains projets pour lesquels je travaille.
Marsh Posté le 04-01-2007 à 01:22:32
++fab a écrit : Je crois bien qu'aucune philosophication d'aucune sorte n'éclipsera le fait qu'une bonne partie de la bibliothèque C est mal foutue, voire inutilisable. |
Faut pas exagérer. Il y a
ce serait intéressant de compléter cette liste, mais je ne pense pas qu'on atteigne 'une bonne partie' de la bibliothèque standard...
Marsh Posté le 04-01-2007 à 07:34:22
Tu peux rajouter strncat -- voir l'avis de Charlie Gordon à ce sujet
Et puis strcpy et strcat, qui ne convenait apparemment pas puisqu'on s'est senti obligé de créer leur version "sécurisé". Je ne juge pas ceux qui l'on fait -- j'aurais sans doute pas fait mieux -- mais ça me fait quand même sourire.
on atteind pas "une bonne partie", mais on tape quand même dans les plus connues
Marsh Posté le 04-01-2007 à 10:17:35
Emmanuel Delahaye a écrit :
|
Ah ??? En quoi est-elle bizarre ça m'intéresse ??? La seule particularité que je lui connaisse qui la différencie des autres fonctions d'écriture de chaîne c'est qu'il lui arrive de ne pas mettre le '\0' (si le nombe "n" est atteint avant la fin de la copie). C'est ça ???
++fab a écrit : Et puis strcpy et strcat, qui ne convenait apparemment pas puisqu'on s'est senti obligé de créer leur version "sécurisé". |
Personnellement je ne suis pas d'accord. Ces fonctions ont créé des trous de sécurité parce que ceux qui les utilisaient les utilisaient mal sans vérifier que la variable réceptrice était sufisemment grande pour recevoir la copie ou, pire, en y mettant des choses provenant de l'extèrieur comme "argv[x]"
C'est donc parce que les programmeurs ont mal fait leur boulot qu'on a dû créer des fonctions le faisant à leur place, ok. Mais ce n'est pas la faute à strcpy() si on l'utilise mal...
Lorsque le C a été créé, son principe était "il accepte tout sans contrôle pour que ce soit très rapide donc à chacun de faire ses propres vérif". On ne peut donc pas en vouloir à ceux qui ont écrit "strcpy()" de n'avoir rien contrôlé...
Bon évidemment ce que j'en dis c'est ce que j'en sais...
Marsh Posté le 04-01-2007 à 11:26:37
bon euh en faite c'est pas trop le sujet , la bibliothèque C , ok ++fab ??
si tu veux tu crée un topic sur ce sujet mais tu viens pas polluer le mien !!!
Marsh Posté le 04-01-2007 à 11:44:26
++fab a écrit : Tu peux rajouter strncat -- voir l'avis de Charlie Gordon à ce sujet |
Je connais ses positions. Personellement, je n'ai pas de problèmes avec cette fonction. Il sufit de lire la doc. Son comportement est on ne peut plus logique. Ce n'est pas le cas de strncpy() qui est tyrès déroutante et que je préfère ne pas utiliser (strncat() est AMA plus adaptée)
Citation : |
Je ne suis pas certain que les fonction strn*() aient été conçues comme des version 'sécurisées'. Il s'agit plutôt d'un mécanisme d'extraction de sous-chaine un peu maladroit...
Citation : on atteind pas "une bonne partie", mais on tape quand même dans les plus connues |
OK. Et alors ? C'est grave ? Si le C ne te plait pas, personne ne t'oblige à en faire. Si les fonctions ne te plaisent pas, écrit les tiennes (je ne me suis pas gêné)
http://mapage.noos.fr/emdel/clib.htm
Module STR
Marsh Posté le 04-01-2007 à 11:49:09
Sve@r a écrit : Ah ??? En quoi est-elle bizarre ça m'intéresse ??? La seule particularité que je lui connaisse qui la différencie des autres fonctions d'écriture de chaîne c'est qu'il lui arrive de ne pas mettre le '\0' (si le nombe "n" est atteint avant la fin de la copie). C'est ça ??? |
Oui, et c'est assez troublant comme mécanisme. En fait il suffit de passer size_dest-1 et ça marche, car la chaine de destination est complétée de zéros.
Marsh Posté le 04-01-2007 à 11:50:17
nicodu95 a écrit : bon euh en faite c'est pas trop le sujet , la bibliothèque C , ok ++fab ?? |
Oui, c'est vrai, ça... Désolé d'avoir contribué à la pollution... Si un modo a le courage de déplacer les posts...
Marsh Posté le 04-01-2007 à 12:49:40
nicodu95 a écrit : bon euh en faite c'est pas trop le sujet , la bibliothèque C , ok ++fab ?? |
T'avais pas une copie à rendre avant 15h45 toi ???
Marsh Posté le 31-12-2006 à 18:35:38
Voila, je suis sous Mandriva 2007 avec gcc version 4.1.1 20060724 (prerelease) (4.1.1-3mdk).
je fais un prog pour calculer les nombres premiers dont voici le code source :
quand je compile il me met ça :
/home/nicolas/tmp/cc1miL25.o: In function `main':
nbprm.c: (.text+0x136): undefined reference to `floor'
collect2: ld returned 1 exit status
je comprend pas parce que j'inclue bien math.h , partout sur le web j'ai lu qu'il fallait l'inclure pour ce servir de floor.
comment faut faire ???
merci d'avance !!!
PS : J'ai essayer de remplacer floor par d'autrers fonctions censées être présente dans math.h mais j'ai toujours le même message
Message édité par nicodu95 le 04-01-2007 à 12:08:38