Publicité
+ Répondre à la discussion Actualité déjà publiée
Page 5 sur 95 PremièrePremière 1234567891555 ... DernièreDernière
Affichage des résultats 81 à 100 sur 1887

Discussion: [Débat] C++ vs Java

  1. #81
    Invité régulier
    Inscrit en
    janvier 2003
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 14
    Points : 6
    Points
    6

    Par défaut

    Ca tient du dialogue de sourd la!
    Pas tant que ça. ++gib affirme avoir décrit un de ces benchmark, ainsi qu'une démonstration. A part celle de l'asm, je n'en voit pas d'autre, j'ai peut-être raté un post ou mal compris qq chose, dans ce cas je présentes mes plus plattes excuses... Enfin soit, mon message allait plus dans le sens qu'il manquait un vrai benchmark...

  2. #82
    Futur Membre du Club
    Développeur Java
    Inscrit en
    janvier 2003
    Messages
    17
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : janvier 2003
    Messages : 17
    Points : 16
    Points
    16

    Par défaut

    Je pense pour ma part que la rapidité d'execution sera de moins en moins un problème, (avec la puissance croissante des ordinateurs et les améliorations nombreuses apportées au JRE et au langage lui même).

    Aujourd'hui il plus d'actualité de confronter JAVA à C# par exemple, puisque le fond de commerce des deux est l'informatique distribuée et les services Web.

    Pour les applications classiques, pas de problème il faut apprendre le C/C++ car des jeux, applications multimedia en JAVA ce n'est surement pas pour demain.

  3. #83
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut cast, arithmetique pointeurs, optimisations, mesure de perf

    Citation Envoyé par Grégory Picavet
    comme tu viens de le démontrer, java est plus fortement typé que le c++ dans le sens ou il produit une erreur et pas un warning.
    La relation "est un" est à prendre au sens objet, c'est à dire "peut se substituer à". En java, il faut effectuer un dynamic cast : int i = (int) 0.5f par ex, car c'est vu comme un transtypage (au sens objet), donc le typage java est plus strict.
    Bonjour Grégory
    Ce n'est pas cool de pinailler. Le fait qu'une problème soit reporté comme
    une erreur ou un avertissement depend simplement des options de compilation,
    c-a-d des souhaits de l'utilisateur. On peut transformer le warning
    gcc en erreur baveuse (option -pedantic-errors la bien nommée),
    ou même n'avoir aucun rapport d'erreur si on le désire.
    Ca n'a pas grand chose à voir avec le langage.
    Ce qui est important c'est que la sémantique du langage fasse que le compilateur
    puisse détecter un problème.
    javac dit "problème potentiel" (il a raison, ce n'est pas
    forcément un problème)
    et gcc dit "attention, assignation d'un double à un int",
    après c'est au programmeur de prendre ses responsabilités.

    Pour la suite de ton intervention, je suis perplexe car
    int i = (int) 0.5f ; est exactement ce qu'on *pourrait* écrire
    aussi en C++ pour être clean avec le compilo.
    Pour cet exemple précis, je parlerais d'ailleurs plutôt de conversion, car
    un "int" n'est pas un objet en Java(1)(2) (pas plus qu'en C++ d'ailleurs).
    On ne peut donc pas parler de relation "est-un" (qui est modélisé par
    l'héritage en programmation objet).
    On a plutôt une relation "peut-etre-converti-en" dans les deux langages
    avec des garde-fous pour éviter de convertir n'importe quoi
    en n'importe quoi.
    C++ propose d'ailleurs la conversion
    static_cast<Type_cible>(expression) servant (je cite) aux
    "conversions bien définies, mais non-sûres".
    Comme nous sommes en plein dans ce cas, ton exemple s'écrirait proprement
    int i = static_cast<int>( 0.5f ) ;
    en C++, ce qui est plus précis que la version Java.

    On dispose aussi de reinterpret_cast, const_cast et dynamic_cast
    pour préciser explicitement ses intentions lors d'un conversion.

    Donc, cher contradicteur, je me permet de nuancer vos affirmations.

    (1) Ceci montre d'ailleurs que la réclame
    "Java est 100% objet" n'engage que ceux qui la croient.
    (2) J'irai plus loin : un String n'est pas un objet non plus, c'est un
    être hybride qui a certaines propriétés des objets et des types natifs.
    ------

    arithmétique des pointeurs ca veut bien dire : si p1, p2 sont des pointeurs alors p1+p2 aussi, p1-p2, p1+1, etc... et donc permettent d'accéder à la mémoire un peu n'importe comment. En java, évidemment, ca n'a aucun sens. l'accès à la mémoire se fait par conteneur (avec get/set). D'ou un accroissement de la sécurité. De plus on peut convertir un tableau de type primitif en son équivalent DirectBuffer (et inversement) dans l'ordre natif des octets de la machine, de manière transparente.
    Oui, etc.. Sauf que :
    1) p1+p2 n'a pas de sens physique (somme de 2 adresses) et ne compile
    même pas.
    2) p1-p2 a un sens mais n'est pas un pointeur, c'est un entier
    (nombre d'éléments entre les deux adresses)
    3) seul, p1+1 est bien un pointeur.
    Dans ces conditions on comprend pourquoi la mémoire est accédée n'importe
    comment.

    Je prédis un "brillant" avenir à ce paquetage. Il est en contradiction
    avec la philosophie de Java.
    est-ce donc que tu reconnais que la philosophie de java est bonne est que le c++ n'a pas de brillant avenir? .Bon évidement c'est pas aussi simple. De plus, les buffer à accès direct ne sont qu'un cas particulier de ce package. Les entrès-sorties étaient le point faible de java. Le package nio permet de réaliser enfin des applications très performantes, capable de monter en charge. Le package io permet de gérer simplement la mémoire avec des performances qui sont bien connues (à cause du blocage avec les threads entre autres)...Le package nio, un peu plus complexe permet de gérer précisement les buffers sans blocage. Les domaines de prédilection de ce package, d'après les cas d'utilisation que l'on peut trouver dans les entreprises, sont les serveurs, le chargement des données en mémoire, etc...
    Quant à la sécurité, je ne sais pas si elle est toujours garantie par rapport aux tiers, chose importante quand on travaille dans une architecture distribuée.
    Bonne dans l'absolu ne signifie pas grand chose (bonne pour quoi ?)
    je veux simplement dire que

    - c'est une porte ouverte à la bidouille
    - sa présence témoigne de la volonté de combler des faiblesses.

    Je pense que Sun devrait s'abstenir de ce genre de chose
    qui ne peut que les décrédibiliser, mais je n'ai
    pas étudié le package d'assez près pour être catégorique.
    Je constate que, toi aussi, tu as un doute sur la sécurité de la chose.
    ------

    En fait le code d'un template n'est compilé que si on réalise une instance de ce template. C'est un peu le point faible car tant qu'aucune instanciation n'est faite, il n'y a aucun moyen de vérifier le type (à chaque techno son inconvénient bien sur).
    Evidemment, puisque les types sont fixés à l'instanciation !
    De toute façon, un code générique non instancié ne risque pas
    plus de générer un erreur d'exécution qu'un programme pas encore écrit.

    pour ceux qui s'intéressent aux templates en java, il existe des projets en cours. http://igm.univ-mlv.fr/~forax/java/jlx/template/paper/Je crois que Sun, si ce n'est pas déjà fait, devrait s'inspirer de ces travaux de recherche qui sont très prometteurs.
    Et bien voila, on y vient! Je me souviens d'une argumentation de pro-Java
    il y a quelques années qui proclamait haut et fort que les templates ne servaient
    à rien en java puisqu'on pouvait fourrer n'importe quel objet dans un conteneur.

    Ceci montre que la véritable puissance d'un langage est avant tout d'être extensible.
    A bon tu connais bcp de langage qui ne sont pas extensibles?
    Tu vois qu'il n'y a pas que les performances dans la vie.
    Plein !!!! (dont un dont le nom commence par J et finit par a).
    Un langage extensible est un langage dans lequel ce que tu développes ne peut
    pas être distingué de ce qui existait avant.
    Un exemple frappant est FORTH : tu peux tout redéfinir (même les structures de contrôle
    en étant habile), et tout ce que tu as développé s'utilise comme du natif. LISP est un
    autre exemple, mais ces deux langages ont en commun une syntaxe extrêmement frustre,
    et d'autres caractéristiques ce qui en limitent l'usage.

    En ce qui concerne C++, les types que tu peux définir s'utilisent exactement
    comme les types natifs (même syntaxe, même façon de les passer en paramètres,
    interface pouvant être basée sur des opérateurs, etc.)
    Leurs performances sont également très proches (tu vois que les perf, dans la vie,
    ça sert, même si il n'y a pas que ça -effectivement-)
    C++ permet également de définir des opérateurs de conversion, etc.
    Tout ceci fait que les types que tu définis sont absolument indiscernables des types
    natifs.
    L'extensibilité c'est ça, et Java ne le fait pas.

    L'extensibilité, c'est aussi de pouvoir implémenter facilement des
    fonctionalités qui nécessiteraient autrement une modification des structure
    de contrôle du langage.
    Par exemple, C++ utilise un concept tout simple, mais très utile : le destructeur.
    Regardes de près Jthreads++ et tu verra qu'il est utilisé pour implémenter les
    sections critiques (synchronized en Java).
    Voila un concept qui a été écarté dans la conception de Java, et qui pourtant
    remplace a lui seul synchronized, finalize() et finally.
    Pas mal pour un truc qui ne sert a rien.
    (Voir dans les post antérieurs mes interventions à ce sujet).
    L'extensibilité, c'est ça et Java ne le permet pas.

    L'extensibilité, c'est aussi que les extensions n'épuisent pas le programmeur
    qui les utilise et la machine qui les exécute.
    Lorque je vois les sinistres bidouilles qu'il faut faire pour
    donner à un "int" une très vague sémantique objet, je pleure :
    conversion en int->Integer, puis Integer->int pour la moindre opération,
    puis retour en Integer, et vlan, la JVM pédale à chaque conversion !
    L'extensibilité, c'est ça et Java ne l'offre pas.

    En plus sans java, JThread n'existerait pas, on peut donc reconnaitre que java propose de bonne idées en programmation.
    J'espère que tu ne veux pas dire que les concepteurs de Java ont inventé les threads ?
    Il s'agit de mise en oeuvre d'un concept qui existaient et avait été implémenté bien avant.
    Le nom Jthreads++ est un nom "commercial" qui rappelle que les fontionnalités sont identiques
    et c'est tout. J'ai fait pendant longtemps des threads en C (pas C++) : c'était beaucoup moins
    commode qu'en Java, mais ça marchait. Il se trouve qu'en C++, c'est aussi commode et qu'il
    n'y a pas eu besoin pour cela de modifier le langage.


    J'affirme qu'en moyenne, on peut s'attendre à obtenir 80 à 100% des performances du c++ optimisé. Maintenant dans l'application que je développe, je ne vais pas m'amuser à la faire en c++ pour le plaisir de faire du benchmark, je m'en fous.
    Ben .. d'accord, mettons que je m'en fiche aussi,
    mais d'ou sortent les 80 à 100% si tu n'as pas essayé ?
    De toute façon le problème réel est ci-dessous.

    Il est notoire que les calculs 3D coûtent cher et doivent
    donc représenter une part importantes des temps d'exécution.
    Je me demande donc si vous n'avez pas mesuré les performance d'open GL
    (qui ne doit pas être écrit en Java, et peut d'ailleurs largement reposer
    sur le matériel) au lieu de celle de votre code.
    Avez vous profilé l'appli pour voir ou se passe le temps d'exécution ?
    Evidemment la librairie opengl pour java est réalisée avec jni. Lors de l'exécution, le JIT optimise les accès comme si ils étaient en natif. Donc les appels de méthodes opengl se font à la même vitesse qu'en c++. Maintenant la perte de performance se fait dans la gestion de la mémoire, d'ou les optimisation que je donne. De plus, il est possible d'améliorer le système de chargement des textures avec nio.
    Quant au profilage, ma foi, il est évident que le goulot d'étranglement est ici la capacité de la carte graphique. TOUS les calculs sont effectués par opengl, donc en natif.
    Si je veux distribuer mon appli, il faut que je fournisse une dll pour windows, une librairie pour linux, pour beos, etc.. qui sont fournies
    Le librairie open GL est *appelée* au travers de JNI (interface avec du code natif)
    elle n'est pas réalisée *avec* JNI; c'est plus qu'une nuance, ça n'a rien à voir.
    Ce que je supposais se vérifie donc, ton appli exécute du code natif (en
    proportion inconnue).

    Le temps que tu as mesuré ne concerne donc pas du code Java mais du code C ou C++
    encapsulé par une surchouche Java. En fait, c'est même peut-être plus compliqué
    si des opérations sont faites par hardware.
    Je trouve assez fort, et carrément non scientifique de prétendre mesurer la rapidité
    d'un langage de cette manière (c-a-d en exécutant du code écrit dans un autre langage)

    Par exemple: (et ce n'est qu'un exemple car je ne connais pas les chiffres réels)

    Supposons que dans une appli C++ utilisant OpenGL, 90% du temps soit consommé
    par openGL et 10% ailleurs (ça me semble être une hypothèse minimale puisque
    tu dis que TOUS les calculs sont faits par openGL.)

    Sur 100s on passe donc
    90s en OpenGL 10s ailleurs.
    Recodons la partie non openGL en Java et *supposons* que celle ci soit 5 fois plus lente
    on obtient donc
    90s en OpenGL 50s ailleurs, soit 140s c-a-d seulement 1,4 fois le temps initial
    ce qui est en contradiction avec notre hypothèse de départ (5 fois).
    Ce type de test ne mesure donc absolument pas les perf du langage.

    On va me rétorquer qu'on en a rien à faire puisque, de toute façon on récupère bien 80à90%
    des perf du C++ pur. Manque de pot, on à perdu au passage tout ce qui fait l'intérêt de Java
    a) la simplicité puisqu'on est obligé de se prendre la tête avec des optimisations,
    des accès direct à je ne sais quoi, des transformations de tables Java en tables natives, etc.
    b) le programme n'a plus l'universalité que devrait fournir la JVM, puisque tu dois fournir
    les bibli openGL (DLL ou .so) pour qu'il tourne. Il se trouve exactement dans la même
    situation que n'importe quel programme compilé, en C++ ou autre, ce qui fait s'effondrer
    tout le modèle java.

    Vrai ou faux ?


    Je crois qu'il ne faut pas avancer comme cela des chiffres qui, si ils
    ne sont pas faux en eux mêmes, ne représentent pas ce qu'ils sont censés
    représenter. Je pense sincérement qu'ils ont été pris pour argent comptant
    et contribuent à alimenter la rumeur.

  4. #84
    Membre éprouvé
    Avatar de grishka
    Inscrit en
    janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 285
    Points : 470
    Points
    470

    Par défaut

    C++
    Code :
    1
    2
    3
    4
    5
    6
    7
    void f&#40;int a, float b&#41; &#123;
    &#125;
    int main&#40;int, char **&#41;
    &#123;
        f&#40;0, 0.5&#41;;
    &#125;
    compilé avec gcc : aucun warning

    JAVA
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    class Test {
        public static void f(int a, float b) {
        }
        
        public static void main(String[] args) {
            f(0,0.5);    
        }
    }
    test.java:7: f(int,float) in Test cannot be applied to (int,double)
    f(0,0.5);
    ^
    1 error


    option -pedantic-errors la bien nommée
    si bien nommée que TOUS les warnings deviennent des erreurs...tip-top!
    Ca n'a pas grand chose à voir avec le langage
    ca a à voir si le langage est strict ou pas
    il a raison, ce n'est pas
    forcément un problème
    Va dire ca aux programmeurs qui font un peu de calcul scientifique.
    après c'est au programmeur de prendre ses responsabilités.
    c'est la philosophie du c++, en effet. Y'a rien à dire de plus

    On ne peut donc pas parler de relation "est-un" (qui est modélisé par
    l'héritage en programmation objet).
    Et alors qui m'empeche de réfléchir en objet, même si je doit coder en procédural après? la méthode d'analyse n'a rien à voir avec l'implémentation, c'est un processus d'abstraction que je trouve élégant et juste d'appliquer à java, même pour le transtypage (OK c'est un peu osé)

    en C++, ce qui est plus précis que la version Java
    oui et qui est inutile en java, car tout est dynamique.
    D'ailleurs puisque qu'on en viens aux cast du c++, bravo on peut par faire de programmation plus dégueulase que ca (transformer des constantes en variables, etC...

    On dispose aussi de reinterpret_cast, const_cast et dynamic_cast
    pour préciser explicitement ses intentions lors d'un conversion.
    bravo, et je suis sûr que comme moi tu sais t'en servir. Mais en java, on s'en fout car tout est dynamique, tout est portable, tout est simple.

    Donc, cher contradicteur, je me permet de nuancer vos affirmations.
    je te permet aussi de prouver les tiennes

    Mais si seulement ca s'arrêtait la, mais non! c++ dispose des opérateurs conversion implicite (avec les constructeurs), Ce qui représente un source de bug perfide pour le non initié puisque le compilateur effectue les transtypage dans votre dos!! OK la parade est d'utiliser le mot-clé "explicit". (Voir le cours c++ pour les pros par Bruno Garcia sur ce site)
    Bref C++ permet bcp de chose par défaut et la seule solution est de connaitre à 100% le langage pour éviter les conneries. Et pour la maintenance d'un programme, prions pour que le programmeur suivant sache aussi bien manipuler le langage.

    "Java est 100% objet" n'engage que ceux qui la croient
    ouaou, mais qui à osé affirmer cette chose ici? personne mon vieux. Tout le monde sait qu'au même titre que c++, c'est un langage ORIENTE objet. Ne reproche pas au gens ce qu'ils n'ont pas dit! c'est facile. Par contre en c++ rien ne t'empeche de faire du procédural (de faire du C quoi), c'est un fait.
    (2) J'irai plus loin : un String n'est pas un objet non plus, c'est un
    être hybride qui a certaines propriétés des objets et des types natifs.
    <mode-provoc>Absolument n'importe quoi, tu baisses dans mon estime. Va revoir tes cours de java, si jamais t'en a déjà eu</mode-provoc>.
    Moi j'en connais un d'être hybride, c'est le c++ TOUT ENTIER.
    Et puis ne dit pas type natif en java, on va te lancer des pierres... dit plutot type primitif car contrairement à c++, les types ne sont pas natifs mais portables (char c'est de l'unicode 16 bit par ex, int c'est 32bits tt le temps, etc...)

    - c'est une porte ouverte à la bidouille
    non, non, au performances.
    - sa présence témoigne de la volonté de combler des faiblesses
    oui, ou est le mal?

    Je pense que Sun devrait s'abstenir de ce genre de chose
    qui ne peut que les décrédibiliser, mais je n'ai
    pas étudié le package d'assez près pour être catégorique
    bravo la c'est toi qui te décrédibilise.

    Je constate que, toi aussi, tu as un doute sur la sécurité de la chose.
    Principe de précaution, esprit cartésien....

    Evidemment, puisque les types sont fixés à l'instanciation !
    Oui et bien justement!
    "Ceci est en contradiction avec le typage statique fort qui garantit la sureté du code en Java"

    Et bien voila, on y vient! Je me souviens d'une argumentation de pro-Java
    il y a quelques années qui proclamait haut et fort que les templates ne servaient
    à rien en java puisqu'on pouvait fourrer n'importe quel objet dans un conteneur.
    moi, je suis pro-java et pro-c++ suivant le contexte de mon application.
    Autant partager au bénéfice de chacun. Ce que je vois, c'est que les templates sont une bonne chose. point barre, on va pas tergiverser la dessus plus longtemps.

    Un langage extensible est un langage dans lequel ce que tu développes ne peut
    pas être distingué de ce qui existait avant
    Ton affirmation est fausse. C++ est paramétrable (redéfinition les opérateurs, des types) par rapport à java. Ce qui apporte une difficulté supplémentaire à la maintenance d'un programme, à sa lisibilité, critères parfois aussi important...Mais comment peux-tu affirmer que java n'est pas extensible, toi qui connait si bien le langage? une librairie n'est-elle pas l'extension d'un langage en cela qu'elle apporte des fonctionnalités de plus haut niveau? quand j'utilise swing, jdbc, hop j'arrete de faire du java . Bref Java n'est pas moins bien, ill est DIFFERENT DANS SA PHILOSOPHIE. Je pense que les programmeurs du langages sont aussi talentueux que ceux du c++, et imposer des contraintes c'est pas pour faire ch.... les programmeurs. C'est pour réfléchir autrement.

    L'extensibilité c'est ça, et Java ne le fait pas.
    Et bien non, c'est pas ca, et java est extensible. C'est pour ca qu'il marche aussi bien.

    sections critiques (synchronized en Java).
    Voila un concept qui a été écarté dans la conception de Java, et qui pourtant
    remplace a lui seul synchronized, finalize() et finally.
    comprends rien, mais vas-y explique moi ce qu'est une section critique est dit moi en quoi c'est pas bien implémenté en java (java c'est nul c bien connu, y'a pas de destructeurs)
    Pas mal pour un truc qui ne sert a rien.
    oulala, en c++ pas de doute un destructeur ca sert, mais en java? non

    J'espère que tu ne veux pas dire que les concepteurs de Java ont inventé les threads
    ben non si tu lis bien
    La facon dont Jthreads++ gère les threads est une réplique de java : synchronized comme moniteur, wait, notify pour la communication entre threads. D'ou l'influence positive de java sur cette librairie.

    mais d'ou sortent les 80 à 100% si tu n'as pas essayé ?
    80à100% c'est ce que J'AI ESSAYE en comparant les tutoriaux écrit en c++ et ceux écrit en java. Pour mon application, je n'ai pas fait de comparaison, évidemment, je n'ai pas le temps. Et je m'attends à ne pas avoir la même vitesse (quoique). Au final il faut tenir compte de tout les modules du jeu qui s'excétent de manière concurrente à openGL.

    Le librairie open GL est *appelée* au travers de JNI (interface avec du code natif)
    elle n'est pas réalisée *avec* JNI
    l'interface est en java, l'implémentation en c/c++, la liaison avec JNI. Pardon pour ce manque de nuance qui n'a aucun impact. Je ne vois pas comment écrire un drivers opengl autrement qu'en natif, mister. D'ou l'utilité du binding. Et puis la surcouche n'est qu'apparente puisque le binding avec le natif est fait à la volée par le JIT compiler.
    Tu voudrais réécrire opengl en java? réfléchit ca n'a aucun sens. A moins que les cartes graphiques embarque un machine virtuelle. argh!

    a) la simplicité puisqu'on est obligé de se prendre la tête avec des optimisations,
    des accès direct à je ne sais quoi, des transformations de tables Java en tables natives, etc.
    La librairie opengl est d'une simplicité à pleurer de bonheur, et s'integre parfaitement à un programme java.
    b) le programme n'a plus l'universalité que devrait fournir la JVM, puisque tu dois fournir
    les bibli openGL (DLL ou .so) pour qu'il tourne. Il se trouve exactement dans la même
    situation que n'importe quel programme compilé, en C++ ou autre, ce qui fait s'effondrer
    tout le modèle java
    La différence est que le code, lui est portable. Je n'ai pas à jouer avec le préprocesseur pour m'en sortir (création d'une fenêtre, basculement plein écran, création des buffers, alignement et ordres des octets, utilisations de librairies de chargement d'images, gestion des E/S, threads lol, etc....)

    Vrai ou faux ?
    devines....

    Je crois qu'il ne faut pas avancer comme cela des chiffres qui, si ils
    ne sont pas faux en eux mêmes, ne représentent pas ce qu'ils sont censés
    représenter
    pur désinformation car j'ai précisé je ne sais combien de fois : ce sont des tests dans le domaines très particulier des jeux vidéos. tu saisies maintenant. Alors c'est pas scientifique?
    En plus je te signale que dans une appli graphique, on mesure le temps de calcul par frame. Opengl travaille en parallèle avec ton application. Pdt qu'opengl se débrouille avec les polygones, toi tu peux faire des calculs d'IA, etc... Au final ca sert à quoi le c++? à avoir plus de temps libre pour ne rien faire?

    Enfin, tout ce qu'on peut dire sur java n'est qu'une accumulation de pinaillage hein, donc j'arrête la, et j'invite les personnes à lire l'excellente FAQ java disponible sur ce site, de même que les cours sur c++ et java (dont certains sous écrits par Ours Blanc Des carpathes alias Bruno Garcia, professeur fabuleux à l'isima, paix à son âme).

  5. #85
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut

    Pas tant que ça. ++gib affirme avoir décrit un de ces benchmark, ainsi qu'une démonstration. A part celle de l'asm, je n'en voit pas d'autre, j'ai peut-être raté un post ou mal compris qq chose, dans ce cas je présentes mes plus plattes excuses... Enfin soit, mon message allait plus dans le sens qu'il manquait un vrai benchmark..
    J'ai du exhumer mon code du fond d'un répertoire, et le toiletter car un certain nombre
    de choses étaient devenues "deprecated". Mais enfin, voici:

    Comme certains ont l'air intéressés, et comme proposé,
    voici un petit code qui permet de vérifier ce que j'avance à propos
    des vitesses respectives de Java et C++.

    Préambule
    ---------
    Ce code ne fait appel aucune bibli (graphique ou autres) qui perturberait
    la mesure car rédigée dans un autre langage.
    Je me suis longuement expliqué sur ceci dans mon dernier post.

    J'ai essayé de réaliser un équilibre en mettant en oeuvre
    - des types natifs (int, double)
    - des types définis par l'utilisateur (on y trouve 2 classes)
    - des conteneurs livrés avec le langage (vector/Vector est le plus courant)

    Conditions expérimentales
    -------------------------
    -J'ai sur mon bureau un P3 1GHz, sous Linux (Mandrake 9) 256Mb de ram
    -Le compilateur Java est celui du JDK 1.3 de Sun,
    la JVM est aussi celle du JDK.
    -Le compilateur C++ est gcc version 3.2 livré avec la distrib Mandrake 9.0

    Les options de compilation sont:
    java : aucune (celles que j'ai essayé n'améliorent pas les perf)
    gcc : -Wall -O1
    -Wall sert juste à demander tous les warnings, et -O1 correspond à
    une optimisation "standard". Elle fait toutefois un boulot énorme
    et sa présence est capitale.

    Ces deux outils ne sont pas les plus performants dans leurs créneaux
    respectifs, mais ils sont sérieux et font référence.
    (En ce qui concerne Java qui n'est pas normalisé, l'implémentation
    de Sun est d'ailleurs la seule référence possible).


    Que fait le programme ?
    -----------------------
    Un calcul géométrique très courant en C.A.O. Il calcule répétitivement
    l'aire d'un polygone plan (non croisé) défini dans l'espace par des points.

    Sommairement décrit, cet algo fait une somme de produits vectoriels.
    Les vecteurs utilisés sont calculés à partir des sommets du polygone,
    et on les obtient (en gros) en faisant la différences des vecteurs de
    position des sommets.
    Le résultat cherché (aire) est la moitié de norme du vecteur somme.

    On fait donc d'un point de vue purement calculatoire
    -des soustraction / additions de doubles (calcul de vecteurs)
    -des produits de doubles (produit vectoriels)
    -une racine carrée.

    Les données d'entrée sont lues dans un fichier (essai.pol)
    et les résultat sont affichés à l'écran. Le programme gère
    lui-même son chronometrage.

    Le chronométrage commence après la lecture du fichier de données et
    s'achève à l'affichage des résultats.

    Le chronométrage ne commence qu'après le lancement du programme,
    ce qui est à priori favorable au programme Java, car on élimine ainsi le
    temps de chargement et de mise en route de la JVM, qui ne sont donc pas
    pris en compte.

    Modélisation objet
    ------------------
    L'identification des concepts indique que l'on manipule

    -des points dans l'espace (plus exactement des vecteurs de position)
    -des polygones

    Les classes développées correspondent exactement à cette analyse.
    Une classe annexe "application" a été developpée en C++ pour être
    conforme à l'esprit objet et une classe "FormattedIStream" en Java
    pour faciliter la lecture du fichier de données.
    ******
    Je réclame aux spécialistes de Java une solution permettant de se passer
    de cette classe.
    ******
    Aucune de ces deux classes ne participe ni n'influe de manière perceptible
    sur les performances.

    Grands principes
    ----------------
    Les deux codes sont écrits selon les mêmes principes, avec les éléments
    que les langages proposent. Le modèle objet est exactement le même
    et j'ai essayé d'être loyal (par exemple, j'ai essayé de limiter le
    nombre de variables intermédiaires au minimim dans les deux cas)
    Si quelque chose ne vous parait pas conforme à ce principe, signalez-le.

    En outre, j'ai essayé de trouver la programmation la plus performante,
    sans céder à la bidouille. Vous verrez que la méthode Polygone.aire
    comporte un code en commentaire qui est significativement moins
    performant que celui qui a été retenu (mais plus facile à comprendre).

    Le code Java est réparti en 4 fichiers, le code C++ est dans un seul
    fichier. L'appli est suffisamment petite pour que ce soit plus
    simple comme ça, et ca vous permettra de compiler/linker en une seule
    commande. Je recommande sous linux.
    gcc -o aire -O1 -Wall aire.cpp -lstdc++

    Pour java
    javac *.java
    java aire
    devrait le faire.

    ====================CODE JAVA========================================
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    // fichier FormattedIStream.java
    import java.io.* ;
    
    // Flot d'entree formatte
    //
    // Je sollicite une solution pour lire le fichier de test
    // sans utiliser  cette classe
    //
    class FormattedIStream extends StreamTokenizer
    &#123;
        private InputStreamReader ist ; 
    
        FormattedIStream&#40; InputStreamReader is&#41;
        &#123;
            super&#40;is&#41; ;
            ist = is ;
            // Valide les "double" comme tokens
            parseNumbers&#40;&#41; ; 
        &#125;
        // Renvoie un double si il existe,
        // ou lance une exception
        double readDouble&#40;&#41; throws IOException
        &#123;
    
            if&#40; nextToken&#40;&#41;== TT_NUMBER &#41;
                return nval ;
            else
            &#123;
                pushBack&#40;&#41; ;
                throw new IOException&#40;"No number on stream."&#41; ;
            &#125;
    
        &#125;
        // Renvoie un int si il existe,
        // ou lance une exception
        int readInt&#40;&#41; throws IOException
        &#123;
    
            if&#40; nextToken&#40;&#41; == TT_NUMBER &#41;
                return &#40;int&#41;nval ;
            else
            &#123;
                pushBack&#40;&#41; ;
                throw new IOException&#40;"No number on stream."&#41; ;
            &#125;
    
        &#125;
        // Renvoie le prochain "mot"
        //
        // Exception si rien à lire ou pas de mot
        String readWord&#40;&#41; throws IOException
        &#123;
            if&#40;nextToken&#40;&#41; == TT_WORD &#41;
                return  sval;
            else
                throw new IOException&#40;"No word on stream."&#41; ;
        &#125;
        //
        // Renvoie la prochaine ligne
        // Exception si rien à lire
        String readLine&#40;&#41; throws IOException
        &#123;
            int car ;
            StringBuffer b = new StringBuffer&#40;&#41;;
    
            while&#40; &#40;car = ist.read&#40;&#41; &#41; != -1 && &#40; car != '\n'&#41;&#41;
                b.append&#40;&#40;char&#41;car&#41; ;
    
            return b.toString&#40;&#41; ;
        &#125;
        // 
        // Vérifie la présence du caractère code
        // le caractere est consomme si il est present
        // tout autre caractere est laisse sur le flot
        // retour &#58; vrai si caractere present
        // Exception si rien à lire
        boolean testChar&#40;int code&#41;  throws IOException
        &#123;
        	boolean yes ;
            if&#40; nextToken&#40;&#41; == code&#41;
                yes =  true;
            else
            &#123;
            	pushBack&#40;&#41; ;
                yes =  false ;
            &#125;
            return yes ;
        &#125;
       
    &#125;
    // ----------------------------------------------------------
    // fichier Point3.java
    import FormattedIStream ;   // Gib made.
    import java.io.* ;       
    
    
    // Classe Point3, et ses operateurs
    class Point3
    &#123;
        private double x,y,z ;
    
        public Point3&#40;&#41;
        &#123;
            x = y = z = 0.0 ;
        &#125;
        public Point3&#40;double xx, double yy, double zz&#41;
        &#123;
            x = xx ; y = yy ; z = zz ;
        &#125;
    
        public String toString&#40;&#41;
        &#123;
            return x + " " + y + " " + z ;
        &#125;
    
        public void readPoint3&#40;FormattedIStream f&#41; throws IOException
        &#123;
            x = f.readDouble&#40;&#41; ;
            y = f.readDouble&#40;&#41; ;
            z = f.readDouble&#40;&#41; ;
        &#125;
    
        public void writePoint3&#40;OutputStreamWriter os&#41; throws IOException
        &#123;
            String s = toString&#40;&#41; ;
    
            os.write&#40;s,0,s.length&#40;&#41;&#41; ;
        &#125;
    
        public Point3 somme&#40; Point3 p2&#41;
        &#123;
            return new Point3&#40;x+p2.x, y+p2.y, z+p2.z&#41; ;
        &#125;
    
        public Point3 diff&#40; Point3 p2&#41;
        &#123;
            return new Point3&#40;x-p2.x, y-p2.y, z-p2.z&#41; ;
        &#125;
    
        public Point3 pvect&#40; Point3 p2&#41;
        &#123;
            Point3 p = new Point3&#40;&#41; ;
    
            p.x = y*p2.z - z*p2.y ;
            p.y = -&#40;x*p2.z - z*p2.x&#41; ;
            p.z = x*p2.y - y*p2.x ;
    
            return p ;
        &#125;
        public double norme&#40;&#41;
        &#123;
            return Math.sqrt&#40;x*x + y*y + z*z&#41; ;
        &#125;
    
        public Point3 dup&#40;&#41;
        &#123;
            return new Point3&#40;x, y, z&#41; ;
        &#125;
    
    &#125;
    // ---------------------------------------------------------------
    // fichier polygone.java
    //
    // Representation d'un polygone 
    // Cette version utilise le conteneur  Vector
    // 
    import Point3 ;
    import java.io.* ;
    import java.util.* ;
    
    class Polygone extends Vector
    &#123;
    
        Polygone&#40;int n&#41;
        &#123;
    		super&#40;5&#41; ;	
        &#125;
    
        public boolean addPoint3&#40;Point3 p&#41;
        &#123;
            addElement&#40;p.dup&#40;&#41;&#41; ; // dup evite les donnees partagees
            return true ;
        &#125;
    	//
        // Il y a ici un mystere &#58; d'apres la doc du JDK, elementAt&#40;&#41; 
        // est cense lancer ArrayIndexOutOfBoundsException.
        // comme at&#40;&#41; ne traite pas l'exception et qu'elle
        // ne la transmet pas non plus, elle ne devrait pas compiler ..
        // Or, elle compile tres bien avec le compilo de Sun
        // J'ai du rater une marche quelque part
        //
        public Point3 at&#40;int i&#41;
        &#123;
                return &#40;Point3&#41;elementAt&#40;i&#41; ;
        &#125;
    
        public void readPolygone&#40;FormattedIStream f&#41; throws IOException
        &#123;            
        	f.ordinaryChar&#40;&#40;int&#41;';'&#41; ; // ; est un token pour ce flot
    
            removeAllElements&#40;&#41;;
        
            Point3 p = new Point3&#40;&#41; ;
            try
            &#123;
                for&#40; ; ;&#41;
                &#123;
                    p.readPoint3&#40;f&#41; ; addPoint3&#40;p&#41; ;
                &#125;
            &#125;
    
            catch&#40;IOException e&#41;
            &#123;
                // on arrive ici si on ne peut plus lire
                // en fait, il n'y a rien de special a faire.
            &#125;
    
            if&#40; ! f.testChar&#40;&#40;int&#41;';'&#41; &#41;
                throw new IOException&#40;"Polygone&#58; ';' not found or syntax error in coordinates."&#41; ;
    
        &#125;
    
        public void writePolygone&#40;OutputStreamWriter os&#41; throws IOException
        &#123;
            int i ;
    
            for&#40;i = 0 ; i < size&#40;&#41; ; ++i&#41;
            &#123;
                at&#40;i&#41;.writePoint3&#40;os&#41; ;
                os.write&#40;"  ",0,2&#41; ;
            &#125;
            os.write&#40;";",0,1&#41; ;
            os.flush&#40;&#41; ;
        &#125;
    
        public double aire&#40;&#41;
        &#123;
            Point3 som = new Point3&#40;&#41; , p0, p1, p2 ;
    
            if&#40; size&#40;&#41; > 2&#41;
    	    &#123;
            /*  // acces par index, grace à la methode at&#40;int&#41;
    	        p0 = at&#40;0&#41; ;
    		    for&#40;int i = 1 ; i < size&#40;&#41;-1 ; ++i&#41;
    		    &#123;
    			    som = 
                    som.somme&#40; &#40;&#40;at&#40;i&#41;.diff&#40; p0&#41;&#41;.pvect&#40;&#40;at&#40;i+1&#41;.diff&#40; p0&#41;&#41; &#41;&#41; &#41;;
    		    &#125;
            */
            
            	// acces par iterateur
            	Enumeration e = elements&#40;&#41; ;
                p0 = &#40;Point3&#41;e.nextElement&#40;&#41; ;
                p1 = &#40;Point3&#41;e.nextElement&#40;&#41; ;
                for&#40; ; e.hasMoreElements&#40;&#41; ; &#41;
                &#123;
                	p2 = &#40;Point3&#41;e.nextElement&#40;&#41; ;
    			    som = 
                    som.somme&#40; &#40;p1.diff&#40; p0&#41;&#41;.pvect&#40;p2.diff&#40;p0&#41; &#41; &#41; ;
                    p1 = p2 ;
    		    &#125;
                    
    		&#125;
    	    return 0.5 * som.norme&#40;&#41; ;
    	&#125;
    &#125;
    // ---------------------------------------------------------------
    // fichier aire.java
    import java.io.* ;
    import FormattedIStream ;
    import java.util.* ;
    
    class aire
    &#123;
        static public void main&#40;String args&#91;&#93;&#41;
        &#123;
            double x = -1;
            long i = -1 , imax = 10000000L ;
    
    
            try
            &#123;
                InputStreamReader f = 
                	new InputStreamReader&#40;new FileInputStream&#40;"essai.pol"&#41;&#41; ;
                FormattedIStream fis = new FormattedIStream&#40;f&#41; ;
    
                double a = 0;
    
                Polygone pol = new Polygone&#40;1000&#41; ;
    
                pol.readPolygone&#40;fis&#41; ;
    
                Date date = new Date&#40;&#41; ; // top chrono ..
    			OutputStreamWriter os = new OutputStreamWriter&#40;System.out&#41; ;
                
                System.out.println&#40; "\nNb de points du polygone &#58;" + pol.size&#40;&#41; &#41; ;              pol.writePolygone&#40;os&#41; ;
    
                for&#40; i = 0 ; i < imax ; ++i&#41;
                    a = pol.aire&#40;&#41; ;
                System.out.println&#40; "\nNb d'iterations &#58;" + imax &#41; ;
                System.out.println&#40; "Aire &#58; " + a &#41; ;
                System.out.println&#40; "Temps ecoule &#58; &#40;" + imax + " iterations&#41; " +
                    + &#40;new Date&#40;&#41;.getTime&#40;&#41;-date.getTime&#40;&#41;&#41;/1000 + " secondes"&#41; ;
                System.out.flush&#40;&#41; ;
            &#125;
    							
     
            catch&#40;Exception e&#41;
            &#123;
                    System.out.println&#40;"Exception&#58; " + e.toString&#40;&#41;
                            + "\n" &#41; ;
            &#125;
        &#125;
    &#125;
    ================================================================== =
    CODE C++
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    //
    // Calcul de l'aire d'un polygone plan
    // dans l'espace -  Sept 97
    //
    // =============================================
    //
    #include <stdexcept>
    #include <string>
    #include <iostream>
    #include <fstream>	
    #include <math.h>	// pour sqrt()
    #include <time.h>	// pour time()
    #include <vector>
    
    using  namespace std ;
    
    // Definition d'une exception "maison"
    class read_error : public runtime_error
    {
    public:
        read_error(string s) : runtime_error(s) {}
    } ;
    // =============================================
    // Representation d'un point
    // (comme etant un vecteur de position)
    // Seuls les operateurs utiles a notre application
    // ont ete implantes.
    class point3
    {
    private:
        double x,y,z ;
        void copy(const point3& pp) // fct de service
        { x = pp.x ; y = pp.y ; z = pp.z ; }
    public:
            
        point3(double xx=0, double yy= 0, double zz=0) 
    	{
            x = xx ; y = yy ; z = zz ;
        }
    
        // contructeur de clonage (inutile)
        point3(const point3& pp) { copy(pp) ; }
        // destructeur (inutile)
        ~point3() {}
    
        // operateur d'affectation (inutile)
        point3& operator=(const point3& pp) { copy(pp) ; return *this ; }
        
        // addition de vecteurs
        point3 operator+(const point3& pp) const
        {
            return point3(x+pp.x, y+pp.y, z+pp.z) ;
        }
        // soustraction de vecteurs
        point3 operator-(const point3& pp) const
        {
            return point3(x-pp.x, y-pp.y, z-pp.z);
        }
        // produit vectoriel
        point3 operator^(const point3& pp) const
        {
            double xx,yy,zz ;
    
            xx = y*pp.z - z*pp.y ;
            yy = -(x*pp.z - z*pp.x );
            zz = x*pp.y - y*pp.x ;
    
            return point3(xx,yy,zz) ;
        }
        // norme d'un vecteur
        double norme() const
        {
            return sqrt( x*x + y*y + z*z) ;
        }
        // operateurs d'entrees/sorties (ce sont des fct amies)
        friend ostream& operator<<(ostream& o, const point3& pp) ;
        friend istream& operator>>(istream& i,  point3& pp) ;
    } ;
    //
    // ___________________________________________________________
    // Les methodes de point3 etant toutes "inline"
    // l'implementation se reduit aux 2 fct amies d'E/S
    //
    ostream& operator<<(ostream& o, const point3& pp)
    {
        return o <<  pp.x << ' ' << pp.y << ' ' << pp.z   ;
    }
    // ___________________________________________________________
    // Les points sont supposes etre formattes
    // sous la forme :     x y z
    // (avec des blancs ou des tab ou des newline entre les coord.)
    istream& operator>>(istream& i, point3& pp)
    {
        double xx,yy,zz ;
    
        if(	(i>>xx) && (i>>yy) && (i>>zz) )
        {
            pp.x = xx ; pp.y = yy ; pp.z = zz ;
        }
        return i  ;
    }
    
    // ==========================================================
    // Representation d'un polygone
    //
    // C'est un ensemble FINI, ORDONNE de points
    // construit par derivation d'un conteneur standard de la stl
    // (vector ou list)
    //
    class polygone : public vector<point3>
    {
    public:
        double aire() const ;
        friend ostream& operator<<(ostream& o , polygone& pp) ;
        friend istream& operator>>(istream& i, polygone& pp) throw (read_error);
    
    } ;
    
    
    ostream& operator<<(ostream& o , polygone& pp)
    {
        polygone::iterator i ;
    
        for(i = pp.begin() ; i != pp.end() ; ++i)
            o << *i << "  "  ;
        return o << ";" << flush ;
    }
    
    // ___________________________________________________________
    // Operateur d'entree: Un polygone est suppose etre
    // formatte sous la forme
    // x0 y0 z0 x1 y1 z1 .... xn yn zn ;
    // (le ; est obligatoire)
    istream& operator>>(istream& i, polygone& pp) throw (read_error)
    {
        point3 p ;
    
        pp.clear() ;	// vide le polygone
        for(  ; (i >> p)  ; )
        {
            pp.insert(pp.end(), p)  ;
        }
        // remettre le flot dans l'etat good
        i.clear() ;
        // lire le separateur ;
        // si il n'est pas present,
        // on met le flot en erreur
        char c = 0;
        if( !(i >> c))
        {   // pas de delimiteur
            throw read_error("Lecture polygone : "
                             "delimiteur  absent") ;
        }
        else if(c != ';') 
        {   // mauvais délimiteur
            i.putback(c) ;
            i.clear(ios::failbit) ; // mettre le flot en etat fail
            throw read_error("Lecture polygone : "
                             "delimiteur incorrect") ;
        }
        return i ;
    }
    //
    // ___________________________________________________________
    // calcul de l'aire d'un polygone
    // il s'agit d'une traduction directe de la
    // formule mathematique
    //
    double polygone::aire() const
    {
        point3 som  ;
    
        if( size() > 2)
        {
        
            const_iterator i = begin(), ip1  ;
            const point3 &first = *i ;
    
            for( ++i, ip1 = i+1 ; ip1 != end() ; ++i, ++ip1)
            {
                som = som + ((*i - first) ^ (*ip1 - first)) ;
            }
        }
        return 0.5 * som.norme() ;
    }
    
    // ================================================================
    // Voici notre application
    //
    class appli
    {
    public:
        // test sur donnees lues dans un fichier, avec chrono
        void start() ;
    } ;
    
    
    // ___________________________________________________________
    void appli::start()
    {
        polygone p  ;
        ifstream f("essai.pol") ;	// ouvrir fichier "essai.pol"
        time_t t ;					// heure, en secondes
        double a ;
        long imax = 100000000 ;
    
        try
        {
    
            if( f.is_open() )
            {	// ouverture reussie
                f >> p ; // lire polygone
                
                t = time(NULL) ; // depart chrono
    
                cout	<< "\nNb de points du polygone : "
                << p.size() << endl << p <<  "\naire : "
                << flush ;
                // beaucoup de calculs, pour que
                // le temps soit mesurable
                for( long i = 0 ; i < imax ; ++i)
                    a=p.aire() ;
    
                cout << a << flush ;
    
                cout << "\nTemps ecoule: (" << imax << " iterations) " 
                << time(NULL) - t
                << " secondes.\n"  << flush ; // arret chrono et affichage
            }
            else
                cout << "\nPb ouverture fichier de test" << flush ;
        }
    
        catch(exception& e)
        {
            cout << "Exception  ("
            << e.what() << ")" << endl << flush ;
        }
    
    }
    
    // ___________________________________________________________
    // main ne sert qu'a lancer l'application
    int main()
    {
        appli benchmark ;
    
        benchmark.start() ;
    
        return 0 ;
    }
    Le fichier de données essai.pol (c'est un carré de coté 10 unités,
    donc on doit obtenir une aire de 100 unités-carré.

    Code :
    1
    2
    3
    4
    5
    0 0 0
    0 10 0
    0 10 10
    0 0 10  ;
    Remarques sur le code
    ---------------------
    Le code C++ est beaucoup plus court (250 lignes contre 315), en partie
    à cause de la classe FormattedIStream.
    Je n'ai pratiquement pas mis de commentaires dans le code Java, un peu dans
    le code C++. Je pense qu'ils sont tous les deux faciles à comprendre,
    mais le code C++ est plus élégant grâce à l'usage d'opérateurs.
    (Voir par exemple la fonction qui calcule l'aire)

    Bien que ceci ne soit pas un soft de production mais juste de démonstration
    j'ai envie qu'il soit correct.
    Vous êtes donc invités à me signaler d'éventuels bugs ou maladresses.

    Les E/S ont été écrites assez rapidement, et utilisent davantage les exceptions
    en Java qu'en C++. Ceci est du au fait qu'il est traditionnel de
    récuperer les erreur de lecture en C++ sans exceptions, alors que c'est le
    contraire en Java. Pour montrer que ça ne pose pas de problème, la classe
    C++ polygone lance une erreur de lecture si la lecture du polygone echoue.
    Je ne me suis pas concentré sur ce point, qui est pour l'instant hors-sujet.

    Le programme C++ fonctionne à l'identique en remplaçant vector par list,
    grâce à l'utilisation des itérateurs. Je suppose qu'il en va de même en Java
    mais je n'ai pas vérifié. Qui veut le faire ?


    Résultats
    ---------
    Java:
    10000000 (10 puissance 7 ) polygones à 4 sommets en 24 secondes

    C++:
    100000000 (10 puissance 8 ) polygones à 4 sommets en 20 secondes
    (J'ai été obligé de multiplier le nb d'itérations par 10 pour avoir plus de
    précision).

    On à donc un rapport de 24/2 = 12

    Ceci est conforme (et au delà) à ce que j'avais annoncé,
    puisque j'ai parlé d'un rapport 10. Je suis conscient que selon
    les outils, on peut avoir des résultats différents, mais ils
    devraient rester du même ordre.

    Je me suis également intéressé au comportement du programme
    lorsque le nombre de points du polygone augmente.
    Voici le résultat en secondes.
    (j'ai ramené a 10000000 itérations par division les perf du C++):

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    Points   C++       Java      Rapport
    ------------------------------------
    4        2.0       24        12
    8        3.9       60        15.38
    16       7.7       140       18.18
    32       15.1      277       18.34
    64       30.1      570       18.93
    Il est à remarquer que
    - le comportement du C++ est linéaire par rapport au nb de points.
    (il a même tendence à s'améliorer lorsque le nb de points augmente)
    - à l'inverse, le comportement du prgm Java se dégrade et tend
    apparemment vers un rapport 19

    Mon interprétation est basée sur le fait que l'augmentation du nb de points
    a tendance à faire diminuer l'influence relative de la boucle principale
    sur l'ensemble du temps. Or cette boucle manipule essenciellement un int
    donc une donnée native. Ce genre de manipulation est le plus rapide car il
    n'y a pas de modèle objet à gérer (juste le coût d'interprétation
    du byte-code).
    Lorsque le programme manipule des objets
    les performances se dégradent, ce qui me semble logique, mais
    est facheux pour un langage à objets.
    Ceci n'est toutefois qu'une idée, et demanderai à être étudié plus finement.

    En C++, le surcoût de l'objet est presque nul, ce qui explique un
    comportement plus linéaire.

    Voila, j'ai essayé d'être complet,
    j'attends vos remarques, qui ne devraient pas tarder à pleuvoir.

    Merci de m'avoir lu.

  6. #86
    Membre émérite

    Inscrit en
    mars 2002
    Messages
    30
    Détails du profil
    Informations forums :
    Inscription : mars 2002
    Messages : 30
    Points : 913
    Points
    913

    Par défaut

    (En ce qui concerne Java qui n'est pas normalisé, l'implémentation
    de Sun est d'ailleurs la seule référence possible).
    ? QUOI ?
    Voila tout ce que tu dois savoir pour ecrire un compilateur ou une machine virtuel : http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html
    Si tu veux des infos sur l'api, il faut matter le javadoc.


    // Il y a ici un mystere : d'apres la doc du JDK, elementAt()
    // est cense lancer ArrayIndexOutOfBoundsException.
    // comme at() ne traite pas l'exception et qu'elle
    // ne la transmet pas non plus, elle ne devrait pas compiler ..
    // Or, elle compile tres bien avec le compilo de Sun
    // J'ai du rater une marche quelque part
    Rien de plus normale... La reponse a ce mistère est expliquer dans le ... Javadoc evidement !
    http://java.sun.com/j2se/1.4/docs/api/java/lang/RuntimeException.html
    Tu voudrais quand meme pas qu'on soit obliger de tagger toutes les classes comme pouvant produire un NullPointerException ?


    Tu n'est pas programmeur C++ pour rien... Je ne vois pas trop l'interet d'hérité de la classe Vector. L'utilisation de Vector est a réservé exclusivement pour de l'acces Multi-Thread, ce n'est pas le cas, donc on utilise ArrayList. Et pour une structure de donnée de taille fixe, preferrera utiliser un tableau...


    La difference de 2 points dans l'espace donne ... un point dans l'espace... Bof !
    Perso je recoderais la fonction pvect pour prendre 4 points et faire le calcul, on economise la construction 2 object intermediaire et on a un object qui ressemble a quelque chose.

    A la place de la salle fonction dup, je ferais plutot un constructeur de recopie, c'est quand meme plus élégant.


    Tu voulais des exemples d'application Java, voila ceux qui tourne tout le temps sur mon PC :
    -> Eclipse, Ide Java open source ( projet initié par IBM )
    -> Jext, un editeur de texte open source
    -> Une interface graphique pour un client p2p.
    -> Un jeu d'echec
    ...

    D'autre gros projet :
    ->JBuilder, IDE java de Borland
    -> NetBeans, IDE java open source (de Sun)
    Je sais, il y a beaucoup d'IDE, mais Java est surtout utilisé pour le developpement des logiciel interne au entreprise, pas trop pour les application a destination des client.

    Autre example concret :
    L'application de gestion de la securité sociale Brésilienne, c'est du 100% Java, toute la chaine en partant de la carte a puce (equivalent de la carte vital) jusqu'au serveur d'application, en passant par les logiciel de traitement des medessin... 12 Millions de personnes.
    On estime aussi a 35 Millions le nombre de telephone portable basé sur J2ME.
    (source Login

  7. #87
    Invité régulier
    Inscrit en
    janvier 2003
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 14
    Points : 6
    Points
    6

    Par défaut

    ORACLE (qui n'est tout de même pas un petit novice), écrit également ses interfaces en java (en tout cas celles que j'ai pu voir, ptet pas celles d'y a quelques années)... Mais je crois que ca ne vaut pas la peine d'en rajouter car de toute manière la discussion a déjà été fermée avant qu'elle puisse commencer avec la phrase ([quote]Alors je poserai la question : en quoi est écrit le moteur qui anime tout ça ?
    )

    Je voudrais égalment rajouter à propos du code, que j'essaie de décortiquer (du code c++ écrit en java) pour l'instant, comporte également quelques méthodes totalement inutilisées (il y a même des méthodes qui étaient déjà en remarque...) ce qui réduit déjà grandement la différence de nombre de lignes de code... (soit une 50ene de lignes pour l'instant soit plus de la moitié de la différence, je n'ai pas compté les remarques personelles, qui concernant java, et non le code la dedans...).

    En réponse à la longueur du code + quelques critiques en passant...
    Pour les méthodes :
    -------------------------------------------------------------------
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Renvoie un int si il existe,
        // ou lance une exception
        /*
        int readInt&#40;&#41; throws IOException
        &#123;
            if&#40; nextToken&#40;&#41; == TT_NUMBER &#41;
                return &#40;int&#41;nval ;
            else
            &#123;
                pushBack&#40;&#41; ;
                throw new IOException&#40;"No number on stream."&#41; ;
            &#125;
    
        &#125;
    et -------------------------------------------------------------------
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //
        // Renvoie la prochaine ligne
        // Exception si rien à lire
        /*
        String readLine() throws IOException
        {
            int car ;
            StringBuffer b = new StringBuffer();
    
            while( (car = ist.read() ) != -1 && ( car != '\n'))
                b.append((char)car) ;
    
            return b.toString() ;
        }
        */
    C'est bien de prévoir mais quand on fait des remarques p/r à la longueur du code....
    -------------------------------------------------------------------
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*  // acces par index, grace à la methode at(int)
               p0 = at(0) ;
              for(int i = 1 ; i < size()-1 ; ++i)
              {
                 som =
                    som.somme( ((at(i).diff( p0)).pvect((at(i+1).diff( p0)) )) );
              }
            */
    Remarques ??? ou oubli???
    ------------------------------
    Code :
    1
    2
    3
    4
    5
       
    public /*boolean*/void addPoint3(Point3 p){
            buffer.addElement(p.dub()) ; // dup evite les donnees partagees
    //        return true ;
        }
    Evidemment on peut rajouter des trucs mais si ca ne vaut pas la peine ...
    ---------------------
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     try
            {
                for( ; ;){
                    p.readPoint3(stream) ;
                    addPoint3(p) ;
                }
            }
    
            catch(IOException e)
            {
                // on arrive ici si on ne peut plus lire
                // en fait, il n'y a rien de special a faire.
            }
    Personellement je ne programme pas avec des for( ; ; ) qui lancent des exceptions à l'intérieur du bloc... Sans doute une pratique c++sienne. Mais ce code se résume à 3- 4 lignes si c'est bien codé... Sans doute que java n'a pas encore permis d'uitliser le goto, alors il faut utilser des rustines...

    ...Dans la methode main .. j'ai pas compris à quoi ca servait

    Les remarques personelles ne concernant pas le code :

    // Il y a ici un mystere : d'apres la doc du JDK, elementAt()
    // est cense lancer ArrayIndexOutOfBoundsException.
    // comme at() ne traite pas l'exception et qu'elle
    // ne la transmet pas non plus, elle ne devrait pas compiler ..
    // Or, elle compile tres bien avec le compilo de Sun
    // J'ai du rater une marche quelque part
    //


    Concernant le code lui-même, déjà une amélioration à faire... Dans une de tes boucles dans la classe Polygone tu crée sans cesse Enumeration (méthode aire)... En remplacant ca par un tableau que tu crées une fois pour toute dans ta méthode readPolygone, ca reduit déjà le temps d'exécution. Donc autrement dit pas besoin d'hériter de Vector, qui pour moi n'est pas une tres bonne idée dans ce cas... suite peut etre dans un prochain épisode

  8. #88
    Invité régulier
    Inscrit en
    janvier 2003
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 14
    Points : 6
    Points
    6

    Par défaut

    Pour le programme java :
    sur ma machine (XP2200,512meg)ca prend 9 secondes

    Après avoir bidouillé un peu dans le code java, j'ai pu constaté que la lenteur de ton programme ne provient même pas des calculs. Bizarre non? Effectivement, j'ai éliminé tous les calculs du programme et c'était toujours aussi lent... En cherchant un peu j'ai remarqué que dans ta classe point3, et cela à peu près dans toutes ses méthodes, tu recréais un objet point3. J'ai remanié un peu le code et en ne créant plus de Point3 à chaque méthode je tombe à 2 secondes (avec le retrait de l'Enumeration qui tu utilisait dans la classe Polygone). Comme quoi, la 'lenteur' de java vient peut-être de la façon de programmer, mais ça à mon avis c'est dans tous les langages. En l'occurance, ici il n'y avait vraiment pas besoin de créer un instance de Point à chaque méthode (pour moi c'est une erreur de conception de la classe Point3 ou une mauvaise connaissance et/ou d'utilisation de l'objet)... Il faudrait donc revoir tes statistiques de performances c++/java un peu à la baisse...

    Je mettrai le code remanié des que j'aurai fini...

  9. #89
    Membre éprouvé
    Avatar de grishka
    Inscrit en
    janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 285
    Points : 470
    Points
    470

    Par défaut

    enfin un benchmark!

    même remarques que Clément et gregy:

    -La classe Vector est prévue pour le multi-threading car les méthodes sont synchronisées.
    -A mon avis l'allocation dynamique d'un nouveau Point3 à chaque opération provoque une saturation du garbage-collector. En c++ les calculs sont fait sur la pile donc la mémoire n'est pas trop sollicité.
    En réécrivant les méthodes pour faire en sorte de ne travailler qu'avec une instance le gain peut dépasser 300% (c'est ce que j'ai remarqué dans mon appli et c'est ce qu'a remarqué gregy). un peu comme ce que j'ai proposé dans un autre message. De plus un appel à new impose une synchronisation avec le garbage-collector.

    Avec tout ca je trouve que java se débrouille plutot bien non ? Maintenant il faudrait refaire les tests.
    Il est a noté que la jre IBM 1.4 sous linux est bien plus rapide et plus optimisée pour le calcul que celle de sun.

    J'ajoute aussi que faire une boucle de 10^8 c'est pas tip top si les données sont toujours les mêmes car tu favorises le cache mémoire. En plus ce n'est pas vraiment représentatif d'une vraie appli de calcul scientifique.Java se débrouille bcp mieux lorsque la taille de la donnée à traiter augmente. Tu remarqueras que plus tu augmente la taille du polygone plus le ratio tend à se stabiliser....

    J'ai effectué les benchmarks plus poussés en analyse numérique proposés sur le site de Scimark 2. On peut y récupérer le code en c et le code java et comparer ses résultats avec ceux dans la base. On peut lancer les tests avec une taille normale et avec une taille large des données.

    On remarque que java se débrouille mieux si la taille des données augmentent. C'est à dire lorsque les calculs sortent du cache mémoire. Java gère mieux la mémoire apparemment.

    Quant à dire si java est plus rapide que le c cela dépend bien sur de votre machine mais il y a plus de chance avec la jre IBM 1.4 sous Linux et un pentium 4 ou un amd athlon. Voili voila.

    perso j'obtient sur un pentium 4 1.7GHz win2K et jre sun 1.4:
    java normal : 129 MFlops
    c normal : 260 MFlops
    java large : 85 MFlops
    c large : 91 MFlops

    sur un amd 1800+ linux mandrake 9 et jre ibm 1.4:
    java normal : 251 MFlops
    c normal : 290 MFlops
    java large : 123 MFlops
    c large : 128 MFlops

    compilé en c avec gcc dans les deux cas avec l'option -03

  10. #90
    mat.M
    Invité(e)

    Par défaut

    ->Les ordinateurs sont de plus en plus puissants donc la rapidité d'exécution est de moins en moins un problème.
    Par pitié n'employez pas des banalités et idioties de ce genre !!
    Qui dit machine plus rapide dit machine faisant tourner des applis plus rapidement que sur d'autres machines .
    Donc gaspillage ENORME au niveau performances.
    Donc environnement de développement ( Java en l'occurence puisque c'est Java dont on parle) peu optimisé ou peu adéquat pour le développement informatique.
    Des machines plus puissantes ????
    J'en viens à me poser la question de savoir à l'heure de .NET ou Java si je ne vais pas me remettre à l'assembleur !
    Je fais une appli de cartographie sous Windows avec API 32 et même ce n'est pas assez performant !
    Pour faire n'importe quel calcul en virgule flottante ou sur des matrices ou je ne sais quoi ,oui Java peut-être plus performant et rapide que le C++.
    Mais tous les tests de comparaisons exposés précedemment sont en ligne de commandes.
    Et pour afficher une fenêtre avec boutons et zones de textes tout le monde sait que ça rame en Java !

  11. #91
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut Conversion de type et passage de paramètres

    Citation Envoyé par Grégory Picavet
    C++
    Code :
    1
    2
    3
    4
    5
    6
    7
    void f&#40;int a, float b&#41; &#123;
    &#125;
    int main&#40;int, char **&#41;
    &#123;
        f&#40;0, 0.5&#41;;
    &#125;
    compilé avec gcc : aucun warning

    JAVA
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    class Test {
        public static void f(int a, float b) {
        }
    
        public static void main(String[] args) {
            f(0,0.5);
        }
    }
    test.java:7: f(int,float) in Test cannot be applied to (int,double)
    f(0,0.5);
    ^
    1 error
    Ton analyse est complètement fausse parceque superficielle.
    Le compilateur n'a pas "négligé" de vérifier les paramètres, il les a convertis !
    Pour vérifier que le compilo ne prend pas les float pour des double
    , remplaçons le passage par valeur par un passage par référence.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void f(float& k)
    {
    }
    
    void g()
    {
      double x = 0;
      f(x) ;
    }
    
    gcc -c conversions.cpp
    conversions.cpp: In function `void g()':
    conversions.cpp:8: could not convert `x' to `float&'
    conversions.cpp:2: in passing argument 1 of `void f(float&)'
    Si tu avais poussé un peu plus tes tests, tu aurais vu que la valeur reçue
    par Test était correcte dans l'exemple que tu donnes,
    donc que le double a bien été converti en float.
    En résumé, pas d'erreur, ni à la compil, ni à l'exec.

    Bon, ceci étant dit, je développe.

    Sémantiquement, un passage de paramètres par valeur est très proche
    d'une affectation(1) : le parametre réel est affecté au paramètre formel.
    Si le paramètre réel peut etre "raisonnablement" converti vers le type du
    paramètre formel compte tenu de ce qu'il connait de ces types, le compilo le fait.

    Dans le contre-exemple que je donne pour monter que C++ vérifie bien les types,
    , ce n'est évidemment pas possible, car le passage par référence
    (physiquement: par adresse)
    conduirait la fonction f() à croire qu'elle reçoit un pointeur sur
    un float alors l'objet pointé est un double.
    Foirage garanti, d'ou cette fois-ci erreur de compil
    (et pas de warning, car ça ne PEUT PAS marcher, c'est donc bien un bug).

    La véritable question soulevée par ton intervention, ce n'est donc pas la vérification
    de type lors des appels de fonctions, c'est la décision de faire une conversion
    de type ou non.

    Tu vas bien sur objecter que ça ne change rien au fait que le passage du double
    à la place du float peut provoquer un débordement, donc une erreur.
    Cela peut effectivement se produire, de la même façon que ça peut se produire dans
    n'importe quelle expression même homogène du point de vue des types.
    Par exemple dans:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    	public  void testDebordement()
    	{
        	  int i = 0  ;
              long k = 0  ;
    
              i =  Integer.MAX_VALUE  + 10 ;
              i = k ;
    	}
    
    x.java:30: possible loss of precision
    found   : long
    required: int
            i = k ;
                ^
    1 error
    La première affectation est accèptée parcequ'elle est homogène du point de vue du type
    (alors même qu'elle ne donnera pas le résultat attendu !)
    alors que la seconde est rejetée (alors qu'elle fonctionnerait parfaitement).
    Cette absurdité montre les limites du typage dans ce cadre, et c'est pour
    ça que C++ n'utilise pas le typage comme cela.

    J'ai ainsi démontré que le refus de conversion entre type compatibles dans une affectation
    n'est ni nécessaire, ni suffisant pour éviter les ennuis.
    Et il en va de même lors d'un passage d'argument par valeur, car celui-ci est une
    affectation.
    Par exemple si f reçoit un int :
    Code :
    1
    2
    	f(Integer.MAX_VALUE  + 10) ; // Aie .....
    on peut prévoir de gros problèmes dans f() alors même que tout semble correct
    lors de la vérification de type.
    Non seulement ce genre d'utilisation du typage est inefficace,
    mais en plus elle est pernicieuse dans la mesure
    ou elle est de nature à donner une fausse impression de sécurité.

    Là ou ça devient comique, c'est que Java pratique la conversion pour les opérandes
    d'opérateurs arithmétiques, mais pas pour l'affectation. Or "=" est bien un opérateur
    (et non une instruction). Il y a là un comportement "non orthogonal", dicté evidemment
    par le désir d'améliorer la "sécurité".

    par exemple dans
    Code :
    1
    2
    3
    int i = 0 ;
    i = i + 3L ; // ne compile pas
    La valeur de i est convertie en long avant l'addition, et le resultat est de type long.
    L'affectation est donc
    refusée, au nom d'une doctrine qui dit qu'on ne peut affecter un long à un int sous peine
    que tout vous saute à la figure.

    Arrivé à ce point de ma réflexion, et ayant constaté la différence de traitement profonde
    entre les deux opérateurs, j'ai essayé ceci :
    Code :
    1
    2
    3
    int i = 0 ;
    i += 2147483648L ; // compile parfaitement
    Ben oui, tu dois être déçu, ça compile très bien. Le code donnant un résultat correct
    ne compile pas et celui qui compile va échouer lamentablement à l'exécution.
    (Les deux codes faisant la même chose, du moins d'un point de vue logique)
    Croustillant non ? Ceci montre que la conception du langage est incohérente.

    Les concepteurs ont fait le choix d'autoriser l'affectation dans ce contexte.
    OK ! , mais ils auraient fait l'autre, ça aurait été aussi mauvais :
    comment expliquer à un programmeur qu'on peut additionner un int et un long
    avec + et pas avec += ?

    Il est cocasse de constater qu'ils ont choisi la rustine la moins voyante,
    mais aussi la moins sûre. Bravo pour un langage qui proclame haut et fort
    qu'il pratique un "typage fort".


    Ceci montre s'il en était encore besoin que l'usage du typage fait par Java pour
    assurer les conversions est mauvais.
    Et je crois qu'il est mauvais car il est dogmatique.
    Les problèmes de conversion sont des problèmes sémantiques ardus. Qui peut réellement
    décider si un type X peut être converti en Y dans telle ou telle condition, sinon
    le programmeur ? Croire qu'appliquer des règles simplistes telles "on ne peut affecter
    un double à un float sous peine de compromettre la sécurité" permet de traiter ce genre de
    questions est une tromperie intellectuelle et une ânerie technique.

    Voila pour l'approche du problème des conversions entre types de base.
    Pour les types définis par l'utilisateur, c'est le néant :
    Pas de conversion possible (encore un manque d'orthogonalité par rapport aux
    types de base), sauf la conversion d'un type dérivé vers un type plus "basique",
    ce qui est une évidence en programmation objet.
    L'approche Java des véritables problèmes est toujours la même :
    circulez, rien à voir.


    Au lieu de cela, C++ part du principe que les conversions sont dangereuses,
    mais pas plus que n'importe quelle autre opération,
    comme je viens de le démontrer.
    On doit donc les intégrer dans l'ensemble du processus calculatoire du programme,
    comme un opérateur de plus.
    Et C++ offre des outils pour cela (conversion par opérateur, conversion par construction)
    qui permettent de préciser la sémantique de conversion (donc d'en augmenter la sécurité).
    Lorsque la conversion automatique est réellement problématique, il est possible
    de demander au programmeur de prendre ses responsabilités (mot clé explicit).
    Enfin, si le transtypage est impossible ou ambigu, C++ te jette, ce qui est une autre manière de te faire prendre tes responsabilités.


    Mais allons plus loin:
    Je pense que le design de Java à ce niveau va bloquer l'évolution du langage
    sur un point au moins.
    Supposons que sous la pression des utilisateurs, SUN veuille ajouter la définition
    d'opérateurs dans les classes. Pourquoi pas ?

    a+b sera alors interprêté comme quelque chose comme operator+(a,b), comme c'est
    le cas en C++ ou en ADA.
    Si a et b sont de types différents, mais potentiellement compatibles, que faire ?
    a) Refuser l'expression. Ce serait incoherent par rapport aux types prédéfinis
    sur lequels Java pratique des conversions.
    b) Convertir les paramètres réels de operator+() vers le type du paramètre formel
    correspondant. C'est ce que fait C++.
    Normalement, et pour être cohérent avec l'application actuelle du typage sur
    les paramètres de fonctions, c'est "impossible" en Java.
    c) Exiger un transtypage manuel. Ceci conduit à un code du style
    X x = (X)a + (X)b ;
    Bonjour le codage! ce n'est pas marrant à utiliser, et ca fait exactement
    ce que fait la solution précédente de façon automatique.


    (1) en fait, il s'agit plus précisément d'une construction.

    option -pedantic-errors la bien nommée
    si bien nommée que TOUS les warnings deviennent des erreurs...tip-top!
    Ma foi, comme tu sembles désirer être materné au point de ne pas vouloir décider
    si un warning vaut la peine d'être pris en compte, ça me semble parfait.

    Ca n'a pas grand chose à voir avec le langage
    ca a à voir si le langage est strict ou pas
    Allons, pas de mauvais esprit! Il y a dans javac une option -nowarn
    pour supprimer les warnings, ça ne change rien au langage !

    il a raison, ce n'est pas
    forcément un problème
    Va dire ca aux programmeurs qui font un peu de calcul scientifique.
    Mince ! Pour une fois que je donne raison à un compilateur Java,
    je me fais tacler ! Tu n'aurais pas un argument un peu moins lapidaire
    et un peu plus clair ?

    après c'est au programmeur de prendre ses responsabilités.
    c'est la philosophie du c++, en effet. Y'a rien à dire de plus
    Le philosophie du C++, c'est surtout de ne pas prendre les programmeurs
    pour des imbéciles en leur faisant prendre des vessies pour des lanternes.

  12. #92
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut

    quote]
    Citation Envoyé par Clement Cunin
    (En ce qui concerne Java qui n'est pas normalisé, l'implémentation
    de Sun est d'ailleurs la seule référence possible).
    ? QUOI ?
    Voila tout ce que tu dois savoir pour ecrire un compilateur ou une machine virtuel : http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html
    Si tu veux des infos sur l'api, il faut matter le javadoc.
    Vous n'avez pas l'air de savoir ce qu'est 'une norme.
    Le document proposé est une spécification SUN, rien de plus.
    Une norme est élaborée de façon publique par un comité genre ISO, AFNOR, ANSI etc..
    Si j'ai le temps, je vous raconterai pourquoi Sun n'a jamais voulu que Java soit normalisé.
    En attendant, je maintiens que l'implémentation de Sun reste la seule référence possible.

    // Il y a ici un mystere : d'apres la doc du JDK, elementAt()
    // est cense lancer ArrayIndexOutOfBoundsException.
    // comme at() ne traite pas l'exception et qu'elle
    // ne la transmet pas non plus, elle ne devrait pas compiler ..
    // Or, elle compile tres bien avec le compilo de Sun
    // J'ai du rater une marche quelque part
    Rien de plus normale... La reponse a ce mistère est expliquer dans le ... Javadoc evidement !
    http://java.sun.com/j2se/1.4/docs/api/java/lang/RuntimeException.html
    Tu voudrais quand meme pas qu'on soit obliger de tagger toutes les classes comme pouvant produire un NullPointerException ?
    Oh ! Quelle déception !
    Dire que je m'étais imaginé que la signature des méthodes renseignait leur utilisateur
    potentiel sur ce à quoi il pouvait s'attendre.
    Je cite un livre qui dit beaucoup de bien de Java:
    "La signature d'une méthode comprends la déclaration des exceptions susceptibles
    de remonter lors de l'appel de cette méthode"
    Bon, je croyais tenir un domaine dans lequel Java était plus clean que C++,
    mais je vois que c'est encore raté.

    Tu n'est pas programmeur C++ pour rien... Je ne vois pas trop l'interet d'hérité de la classe Vector. L'utilisation de Vector est a réservé exclusivement pour de l'acces Multi-Thread, ce n'est pas le cas, donc on utilise ArrayList. Et pour une structure de donnée de taille fixe, preferrera utiliser un tableau...
    L'intérêt, c'est d'offrir à l'utilisateur les outils de manipulation d'éléments
    offert par Vector pour manipuler les polygones.
    Si je n'avais pas voulu cela, Polygone aurait juste utilisé un Vector en interne
    et aurait du fournir des fonctions d'accès. Cela aurait encore ralenti cette classe,
    alors ne vous plaignez pas.

    A propose de ArrayList, vous auriez du essayer avant de proposer cette "optimisation"
    ArrayList n'a pas la même interface que Vector : j'ai du remplacer ce qui suit
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
        	
            add&#40;p.dup&#40;&#41;&#41; ; // dup evite les donnees partagees
            //addElement&#40;p.dup&#40;&#41;&#41; ; // dup evite les donnees partagees
    
                //return &#40;Point3&#41;elementAt&#40;i&#41; ;
                return &#40;Point3&#41;get&#40;i&#41; ;
    
            // removeAllElements&#40;&#41;;
            removeRange&#40;0,size&#40;&#41;&#41; ;
    Comme je n'ai pas trouvé d'accès par itérateur, j'ai du remplacer l'accès par itérateur par
    l'accès via la méthode at() (qui utilise get() et réalise le transtypage).
    Si vous voyez un autre moyen, je suis preneur.

    Le résultat des courses, c'est qu'il faut 27 secondes au lieu de 24 secondes pour réaliser le test le plus court. Je suis peut-être qu'un programmeur C++, mais je teste avant de dire une bêtise.

    En ce qui concerne la taille fixe, merci, je me doute bien qu'un tableau serait plus efficace.
    Mais la taille n'est pas fixe.

    La difference de 2 points dans l'espace donne ... un point dans l'espace... Bof !
    Relisez ce que j'ai écrit
    Code :
    1
    2
    3
    4
    5
    6
    ------------------ 
    L'identification des concepts indique que l'on manipule 
    
    -des points dans l'espace (plus exactement des vecteurs de position) 
    -des polygones
    Perso je recoderais la fonction pvect pour prendre 4 points et faire le calcul, on economise la construction 2 object intermediaire et on a un object qui ressemble a quelque chose.
    Je ne comprends pas du tout, et je vous invite à me monter ce que
    vous voulez dire.

    A la place de la salle fonction dup, je ferais plutot un constructeur de recopie, c'est quand meme plus élégant.
    Plus élégant ?
    Cela conduit à ecrire
    au lieu de
    Je veux bien, mais ça ne me parait pas evident.

  13. #93
    Membre éprouvé
    Avatar de grishka
    Inscrit en
    janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 285
    Points : 470
    Points
    470

    Par défaut

    Si j'ai le temps, je vous raconterai pourquoi Sun n'a jamais voulu que Java soit normalisé.
    Non il vaut mieux lire directement le rapport officiel :
    http://java.sun.com/pr/1999/12/pr991207-08.html

    Même s'il n'y a pas de normalisation, la spécification de la plateforme java2 permet de maintenir des implémentations cohérentes de la part des constructeurs.
    Weblogic, webSphere, jboss, sun one (encore heureux!), borland appserver, etc... sont des serveurs d'application respectant la spec j2EE . Cela dit, on parle couramment de norme j2EE, même si elle n'est pas validée pas un organisme. Tout le monde peut télécharger la spéc j2ee et commencer à faire son serveur d'application (bon courage quand même). c'est valable pour une machine virtuelle aussi. Un programme java compile et se comporte de la même manière avec la jre ibm ou sun....


    ArrayList n'a pas la même interface que Vector
    elles implémentent java.util.List.... (cf le code ci-dessous)


    Avec ce code :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    import java.util.*;
    
    class Test &#123;
        static final long dt = 3000;
        
        public static void main&#40;String&#91;&#93; args&#41; &#123;
            int iter=0;
            
            if&#40;args&#91;0&#93;.equals&#40;"vector"&#41;&#41;&#123;
                Vector vec = new Vector&#40;&#41;;
                
                for&#40;int i=0;i<1000; ++i&#41;
                    vec.add&#40;new String&#40;"hello"&#41;&#41;;
                
                long t0=System.currentTimeMillis&#40;&#41;;
                while&#40;System.currentTimeMillis&#40;&#41;-t0<dt&#41; &#123;
                    for&#40;int i=0; i<vec.size&#40;&#41;; ++i&#41;&#123;
                        String s = &#40;String&#41; vec.get&#40;i&#41;;
                    &#125;
                    ++iter;
                &#125;
            &#125; else &#123;
                ArrayList list = new ArrayList&#40;&#41;;
                
                for&#40;int i=0;i<1000; ++i&#41;
                    list.add&#40;new String&#40;"hello"&#41;&#41;;
                
                long t0=System.currentTimeMillis&#40;&#41;;
                while&#40;System.currentTimeMillis&#40;&#41;-t0<dt&#41; &#123;
                    for&#40;int i=0; i<list.size&#40;&#41;; ++i&#41; &#123;
                        String s = &#40;String&#41; list.get&#40;i&#41;;
                    &#125;
                    ++iter;
                &#125;
            &#125;
            
            System.out.println&#40;iter+" iterations"&#41;;
        &#125;
    &#125;
    j'obtient environ 71500 iterations sur les Vector et 96600 avec ArrayList
    Soit un gain de 35%.

    Maintenant avec les iterateurs, Vector reste constant et ArrayList descend à 51705. Soit une perte de 28%

    Comment expliquer ca? Y'a -til une optimisation faites par la jvm?


    Ca n'empeche pas que le vrai gain se situe coté mémoire...Faire attention à ne pas saturer inutilement le garbage-collector.

    Le compilateur n'a pas "négligé" de vérifier les paramètres, il les a convertis !
    donc que le double a bien été converti en float.
    Super, c'est exactement ce que je voulais montrer. C'est la même histoire avec les convertions implicites que le compilateurs réalise derrière votre dos. Une petite erreur de frappe, et hop un bug pernitieux. Ici ca n'est pas grave. Dans un logiciel de calcul peut-être plus. Non le pire vient avec les opérateurs de conversion implicite
    ca a à voir si le langage est strict ou pas
    Allons, pas de mauvais esprit! Il y a dans javac une option -nowarn
    pour supprimer les warnings, ça ne change rien au langage !
    Le philosophie du C++, c'est surtout de ne pas prendre les programmeurs
    pour des imbéciles en leur faisant prendre des vessies pour des lanternes.
    a bon, en c++ tu peux tout convertir en n'importe quoi. (un pointeur en entier, une référence en void *, des constantes en variables). Sans aucun warning!

    Et puis :
    byte i=0;
    i = i+3L ne marche pas car le compilo voit que le calcul doit se faire en long sans perte de précision, mais l'affectation risque de provoquer une perte de précision. d'ou erreur.
    byte i=0;i+=128L; ca marche car on incrémente par une constante vue comme un octet avec la formule : (constante modulo 128) - 128. C'est circulaire si tu veux.
    Regle : les affectations de variables doivent être cohérentes en type. Les incrémentations, et autres opérations *=, /=, sont calculées au modulo prés. Comme ce que j'ai montré dans mon précédent exemple, pas de conversion implicite par affectation, donc plus strict que c++.
    C'est simplement une règle du compilo, ou est l'erreur la? Ca permet de calculer simplement des offsets dans un tableau en faisant des additions avec un modulo effectué gratuitement plutot que "le reste de la division entière de ....blablabla".




    L'approche Java des véritables problèmes est toujours la même :
    circulez, rien à voir.
    Simplicité => efficacité
    Le c++ permet de gérer plus finement les conversions (et offre la possibilité de faire n'importe quoi), d'ou une attention particulière de la part du programmeur.
    Généralement, les simplifications proposées sont difficilement maintenable; ce qui est maintenable, c'est un code simple et clair. Ce qui est parfois incompatible avec les performances.

  14. #94
    Invité régulier
    Inscrit en
    janvier 2003
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 14
    Points : 6
    Points
    6

    Par défaut

    bon pour le code ... avant toute chose, ce code n'a aucun but d'estétique informatique. Etant donné que ce ne sont ni mes classes et que dans la vie de tous le jours je ne programmes pas des appli de ""géométrie"" qui calculent des aires... En résumé j'ai bidouillé autour de l'existant juste pour montrer que la facon de coder peut grandement améliorer les soit disantes "mé-performances" de java... Mais d'autres façons de faire existent, il y a certainement moyen de faire beaucoup plus beau et certainement encore plus performant, voir certaines autres remarques, là n'était pas mon but ...

    classe aire
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    import java.io.* ;
    import java.util.* ;
    
    class Aire&#123;
    
        private static long ITERATIONS = 10000000L;
    
        public static void main&#40;String args&#91;&#93;&#41;&#123;
            try&#123;
                InputStreamReader f = new InputStreamReader&#40;new FileInputStream&#40;"essai.pol"&#41;&#41; ;
                FormattedIStream fis = new FormattedIStream&#40;f&#41; ;
    
                double a = 0;
    
                Polygone pol = new Polygone&#40;&#41; ;
    
                pol.readPolygone&#40;fis&#41; ;
    
                long date = System.currentTimeMillis&#40;&#41; ; // top chrono ..
                OutputStreamWriter os = new OutputStreamWriter&#40;System.out&#41; ;
    
                System.out.println&#40; "\nNb de points du polygone &#58;" + pol.getSize&#40;&#41; &#41; ;
                pol.writePolygone&#40;os&#41; ;
    
                for&#40; int i = 0 ; i < ITERATIONS ; ++i&#41;&#123;
                  a = pol.aire&#40;&#41; ;
                &#125;
                System.out.println&#40; "\nNb d'iterations &#58;" + ITERATIONS &#41; ;
                System.out.println&#40; "Aire &#58; " + a &#41; ;
                System.out.println&#40; "Temps ecoule &#58; &#40;" + ITERATIONS + " iterations&#41; " +
                    + &#40;System.currentTimeMillis&#40;&#41;-date&#41;/1000 + " secondes"&#41; ;
                System.out.flush&#40;&#41; ;
            &#125;
    
    
            catch&#40;Exception e&#41;
            &#123;
              e.printStackTrace&#40;&#41;;
                    System.out.println&#40;"Exception&#58; " + e.toString&#40;&#41;
                            + "\n" &#41; ;
            &#125;
        &#125;
    &#125;
    classe polygone
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    import java.io.* ;
    import java.util.* ;
    
    class Polygone{
    
      private Point3[] arrayOfPoints = null;
      private Vector buffer = null;
    
      public Polygone(){
        this.buffer = new Vector();
      }
    
      public void addPoint3(Point3 p){
        //buffer.addElement(p.dub()) ; // dup evite les donnees partagees
        buffer.addElement(p) ;
      }
    
      public Point3 at(int i){
        return (Point3)buffer.elementAt(i) ;
      }
    
      public void readPolygone(FormattedIStream stream) throws IOException {
         stream.ordinaryChar((int)';') ; // ; est un token pour ce flot
    
          buffer.removeAllElements();
    
          Point3 p = new Point3() ;
          try{
              for( ; ;){
                  p.readPoint3(stream) ;
                  addPoint3(p.dub()) ;
              }
          }catch(IOException e){
              // on arrive ici à cause d'une programmation brol
          }
    
          if( ! stream.testChar((int)';') )
              throw new IOException("Polygone: ';' not found or syntax error in coordinates.") ;
    
          toPoint3Array();
      }
    
      private void toPoint3Array(){
        this.arrayOfPoints  = new Point3[this.buffer.size()];
    
        this.buffer.trimToSize();
    
        Enumeration e = this.buffer.elements();
        for(int i = 0; e.hasMoreElements(); i++){
          Point3 p = (Point3)e.nextElement();
          this.arrayOfPoints[i] = p ;
        }
      }
    
      public void writePolygone(OutputStreamWriter os) throws IOException{
        int i ;
    
        for(i = 0 ; i < this.buffer.size() ; ++i){
            at(i).writePoint3(os) ;
            os.write("  ",0,2) ;
        }
        os.write(";",0,1) ;
        os.flush() ;
      }
    
      public double aire(){
        Point3 som = new Point3();
        Point3 produit = null;
        Point3 p0 = null;
        Point3 p1 = null;
        Point3 p2 = null;
    
        if( this.arrayOfPoints.length > 2){// acces par tableau
    
            p0 = this.arrayOfPoints[0].getInitialValue();
            p1 = this.arrayOfPoints[1].getInitialValue();
    
            for(int i = 2 ; i < this.arrayOfPoints.length ; i++ ){
              p2 = this.arrayOfPoints[i].getInitialValue();
              p1.difference(p0);
              p2.difference(p0);
              p1.produitVectoriel(p2);
              som.somme(p1);
              p1 = p2 ;
            }
        }
         return 0.5 * som.norme() ;
      }
    
      public int getSize(){
        return this.buffer.size();
      }
    
    }
    classe point3
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    import java.io.*;
    
    // Classe Point3, et ses operateurs
    class Point3{
        private double initialX = 0.0d ;
        private double initialY = 0.0d;
        private double initialZ = 0.0d;
        private double x = 0.0d ;
        private double y = 0.0d;
        private double z = 0.0d;
    
        public Point3(){}
    
        public Point3(double x, double y, double z){
            this.initialX = this.x = x ;
            this.initialY = this.y = y ;
            this.initialZ = this.z = z ;
        }
    
        public String toString(){
            return x + " " + y + " " + z ;
        }
    
        public void readPoint3(FormattedIStream f) throws IOException{
            this.initialX = x = f.readDouble() ;
            this.initialY = y = f.readDouble() ;
            this.initialZ = z =  f.readDouble() ;
        }
    
        public void writePoint3(OutputStreamWriter os) throws IOException{
            String s = toString() ;
            os.write(s,0,s.length()) ;
        }
    
        public void somme(Point3 point){
          this.x += point.x;
          this.y += point.y;
          this.z += point.z;
        }
    
        public void difference(Point3 point){
          this.x -= point.x;
          this.y -= point.y;
          this.z -= point.z;
        }
    
        public void produitVectoriel(Point3 point){
            double tmpX = this.y * point.z - this.z * point.y ;
            double tmpY = -( this.x * point.z - this.z * point.x) ;
            double tmpZ = this.x * point.y - this.y * point.x ;
    
            this.x = tmpX;
            this.y = tmpY;
            this.z = tmpZ;
        }
    
        public double norme(){
          return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z) ;
        }
    
        public Point3 dub(){
          return new Point3(x,y,z);
        }
    
        private void initValues(Point3 point){
          this.x = point.x;
          this.y = point.y;
          this.z = point.z;
        }
    
        private void initValues(double x, double y, double z){
          this.x = x;
          this.y = y;
          this.z = z;
        }
    
        public void resetInitialValues(){
          initValues(this.initialX, this.initialY, this.initialZ);
        }
    
        public Point3 getInitialValue(){
          this.resetInitialValues();
          return this;
        }
    
    }
    le stream
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    import java.io.StreamTokenizer;
    import java.io.*;
    
    
    class FormattedIStream extends StreamTokenizer
    {
        private InputStreamReader ist ;
    
        FormattedIStream( InputStreamReader is){
            super(is) ;
            ist = is ;
            // Valide les "double" comme tokens
            this.parseNumbers() ;
        }
        // Renvoie un double si il existe,
        // ou lance une exception
        double readDouble() throws IOException
        {
    
            if( nextToken()== TT_NUMBER )
                return nval ;
            else
            {
                pushBack() ;
                throw new IOException("No number on stream.") ;
            }
    
        }
    
        // Exception si rien à lire ou pas de mot
        String readWord() throws IOException{
            if(nextToken() == TT_WORD )
                return  sval;
            else
                throw new IOException("No word on stream.") ;
        }
        // Vérifie la présence du caractère code
        // le caractere est consomme si il est present
        // tout autre caractere est laisse sur le flot
        // retour : vrai si caractere present
        // Exception si rien à lire
    
        boolean testChar(int code)  throws IOException
        {
           boolean yes ;
            if( nextToken() == code)
                yes =  true;
            else
            {
               pushBack() ;
                yes =  false ;
            }
            return yes ;
        }
    
    }
    sur ma machine
    code ++gib : 4 points prennent 9 secondes à s'exécuter
    8 points prennent 25 secondes à s'exécuter
    mon code : 4 points prennent 2 secondes à s'exécuter
    8 points prennent 5 secondes à s'exécuter

    déolé je n'ai pas eu le courage de créer un fichier avec 64 points ....

    La principale adaptation a été d'enlever la création d'instances de point3 dans énormément de méthodes.
    je passes de 90000005 à 10000005 (= nombre d'iterations (le résutat de la somme) + les 4 points + 1?)instanciations soit un facteur de 9, que je suis sur qu'il y a moyen d'améliorer encore car ca me semble beaucoup pour 'l'exercice' en question. Si mes calculs sont bons il n'en faudrait que 5 (pour 4 points), ce qui est faisable assez facilement (Là je rejoint l'avis de clément, il faudrait une méthode permettant d'envoyer plusieurs points dans la méthode aire, sans devoir pour autant à chaque fois réinstancier l'objet Point3).... Alors java n'est pas performant avec les objets?? Evidemment quand programme à la façon sauvage, on obtient des résultats médiocres...

  15. #95
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut

    Je voudrais égalment rajouter à propos du code, que j'essaie de décortiquer (du code c++ écrit en java) pour l'instant, comporte également quelques méthodes totalement inutilisées (il y a même des méthodes qui étaient déjà en remarque...) ce qui réduit déjà grandement la différence de nombre de lignes de code... (soit une 50ene de lignes pour l'instant soit plus de la moitié de la différence, je n'ai pas compté les remarques personelles, qui concernant java, et non le code la dedans...).
    On ne fait pas le concours du nombre de lignes je crois ?
    Le but est de mesurer les perfs. Si le code n'est pas utilisé,
    il ne doit pas avoir beaucoup d'influence sur les perfs.

    J'ai fait un copier/coller de mes fichiers, et j'aurais du retirer
    les méthodes inutilisées, mais ça ne change rien au résultat.

    Au passage, j'aurais préferé qu'on m'indique comment me passer de
    FormattedIStream. J'ai developpé ce truc pour faire ce que je fais
    en 1 ligne de C++, et je ne le trouve pas particulièrement beau.
    En effet, je me tape l'empilement de
    FileInputStream +
    InputSteamReader +
    FormattedIStream (qui utilise en interne StreamTokenizer)
    OUF !!
    Tout cela pour lire des double dans un fichier formatté !
    Après cela, dire que Java est simple fait rigoler.
    Il est tellement "simple" que toute la complexité est reportée
    sur les bibliothèques.

    Je pense d'ailleurs que FormattedIStream est mal conçue : elle ne devrait
    utiliser les exceptions que pour les erreurs "hardware"
    et non pour les erreurs de formattage (mais ça, personne ne me l'a dit,
    occupés que vous êtes à "gratouiller" le code pour gagner les précieuses
    secondes).
    Voila en tout cas ce qui arrive lorsqu'un outil n'est pas assez puissant :
    on perd son temps sur les à-cotés au lieu de se concentrer sur
    le problème posé.

    -------------------------------------------------------------------
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*  // acces par index, grace à la methode at&#40;int&#41;
               p0 = at&#40;0&#41; ;
              for&#40;int i = 1 ; i < size&#40;&#41;-1 ; ++i&#41;
              &#123;
                 som =
                    som.somme&#40; &#40;&#40;at&#40;i&#41;.diff&#40; p0&#41;&#41;.pvect&#40;&#40;at&#40;i+1&#41;.diff&#40; p0&#41;&#41; &#41;&#41; &#41;;
              &#125;
            */
    Remarques ??? ou oubli???
    Ni l'un ni l'autre. C'est une version qui fait de l'accès direct
    (ie: par index) au conteneur.
    Pas utilisée car 10% plus lente. J'ai du d'ailleurs la remettre en service
    pour utiliser un ArrayList.

    ------------------------------
    Code :
    1
    2
    3
    4
    5
       
    public /*boolean*/void addPoint3(Point3 p){
            buffer.addElement(p.dub()) ; // dup evite les donnees partagees
    //        return true ;
        }
    Evidemment on peut rajouter des trucs mais si ca ne vaut pas la peine ...
    Exact ! On supprime, c'est une scorie d'une version antérieure.
    On gagne combien de secondes là ?

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     try
            {
                for( ; ;){
                    p.readPoint3(stream) ;
                    addPoint3(p) ;
                }
            }
    
            catch(IOException e)
            {
                // on arrive ici si on ne peut plus lire
                // en fait, il n'y a rien de special a faire.
            }
    Personellement je ne programme pas avec des for( ; ; ) qui lancent des exceptions à l'intérieur du bloc... Sans doute une pratique c++sienne. Mais ce code se résume à 3- 4 lignes si c'est bien codé... Sans doute que java n'a pas encore permis d'uitliser le goto, alors il faut utilser des rustines...

    Pour la version C++, il suffit de la regarder au lieu de calomnier :
    Code :
    1
    2
    3
    4
    5
        for(  ; (i >> p)  ; )
        {
            pp.insert(pp.end(), p)  ;
        }
    Encore qu'on puisse probablement faire encore plus simple.



    ...Dans la methode main .. j'ai pas compris à quoi ca servait
    A rien bien sûr, c'est encore un reste d'une version antérieure.

  16. #96
    Membre éprouvé
    Avatar de grishka
    Inscrit en
    janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 285
    Points : 470
    Points
    470

    Par défaut

    Une exception devrait se produire seulement si le nombre de token numérique avant chaque ';' n'est pas un multiple de trois.

    pour eviter de terminer une boucle par une exception , un truc dans ce style :

    while( stream.hasMorePolygons() ) {
    }


    FileInputStream +
    InputSteamReader +
    FormattedIStream
    Pourquoi le InputStreamReader ici?


    Il est tellement "simple" que toute la complexité est reportée
    sur les bibliothèques
    Le design pattern Decorateur permet d'ajouter dynamiquement des fonctionnalités à une hiérarchie de classe. c'est une approche différente du c++.
    avantages/inconvénients :
    Comme avec les Lego(tm), tu peux interconnecter plusieurs décorations avec une classe de départ pour obtenir toute les combinaisons possibles moyennant très peu de classes (classes de départ, et classes de décoration). En héritage simple, cela aurait donné une progression exponentielle du nombre de classe pour chaque nouvelle fonctionnalité. De plus pour le nommage des classes, ca aurait été compliqué.
    L'inconvénient de cette flexibité est un code plus lourd.


    *InputStream classe de base pour les flux de données entrant.
    Classe dérivant de inputStream :
    -FileInputStream : lire un fichier.
    -StringBufferInputStream : lire une chaine de charactere comme un flux

    *Decorateurs (classes dérivant de InputStream et possédant une référence sur un InputStream, permettant d'utiliser le comportement de base)
    -ObjetInputStream : lire un objet en version sérialisée provenant de n'importe quel inputStream éventuellement luî même décoré.
    -BufferedInputStream : fait la même chose que le flux de base référencé, mais utilise un buffer
    -CheckedInputStream : utilisé pour zipper un flux
    ....

    Pareil pour outputStream...

    Swing utilise pas mal ce concept.

  17. #97
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut

    Citation Envoyé par gregy
    bon pour le code ... avant toute chose, ce code n'a aucun but d'estétique informatique.
    Et bien, avant toute chose : heureusement.


    Sur le fond:
    ------------

    Je croyais avoir clairement énoncé les rêgles permettant une comparaison
    objectives des performances de deux langages (ce que personne n'a contesté).


    Or te voila parti dans une course à l'optimisation en bidouillant
    le code à mort (le terme "bidouiller" est de toi, mais il est approprié).
    Que crois tu avoir prouvé ? Que Java est un langage très rapide ?
    Quelle naiveté !
    Il ne t'est pas venu à l'idée qu'il est possible de bidouiller des deux cotés ?
    (Quoique bidouiller autant me parait difficile)


    La rêgle de base est que les deux programmes fassent la même chose
    pour qu'on puisse les comparer. Si ce n'est pas le cas, on sodomise
    les insectes, rien de plus.

    Voici ce que tu as fait (je reconstitue ton cheminement intellectuel)

    Acte 1
    ------
    Les objets coûtant cher en Java, tu as décidé de mener les calculs
    sur des tableaux plutôt que sur des vecteurs. Tu as donc introduit un
    tableau de Point3 (structure de donnée de bas niveau) dans la classe polygone.
    Manque de pot, ceci revient à gérér la mémoire "à la main" puisqu'un
    tableau doit être dimensionné explicitement. Bref comme en C (pas C++).
    Donc tu as l'idée de garder le Vector, a coté du tableau et de recopier
    le Vecteur dans le tableau juste après la lecture du fichier (toPoint3Array()).

    Vlan, une méthode de plus et deux structures de données utilisées en
    parallèle. D'ou perte de place et problèmes de cohérence en perspective.

    En effet, ainsi "équipé" le Polygone ne peut plus être modifié
    (ajout/suppression de points) sous peine d'introduire une incohérence
    entre le tableau et le Vector.
    Quelle belle conception.

    Acte 2
    ------
    Les objets coutant cher en Java, tu as aussi l'idée d'en limiter
    la manipulation dans la méthode calcul Polygone.aire(), en ne créant
    pas d'objet intermédiaire pour stocker les résultats intermédiaires.
    Quelle bonne idée !
    Pour y parvenir, tu décide de changer la sémantique de add qui
    passe de simple addition (+) à addition-rangement (+=), de façon à
    mener le calcul sur les Point3 du tableau eux-mêmes.
    Même opération sur le produit vectoriel.
    Stop !
    Ici, ton programme ne fait plus la même chose qu'avant et en étant
    honnête, tu aurais du faire le même type de modif sur la version C++.
    Tu aurais alors constaté une accélération de celle-ci.

    Mais le pire reste à venir. Ayant fait cela, tu as constaté que le
    ton programme ne marchait plus.

    Acte 3
    ------
    Phase de "débuggage".
    Ton (nouvel) algo fonctionne une fois, et échoue les 9999999 autres.
    La raison en est simple : comme tu fais les calculs en utilisant
    les points du polygone commes variables intermédiaires
    , le polygone
    est détruit à l'issue du premier calcul.
    Au lieu de constater ton erreur et d'essayer une autre solution,
    tu persistes en bidouillant la classe "Point3", qui jusqu'ici avait
    echappé à ta fureur optimisatrice.
    Commes les Point3 sont écrasés tu imagines de dupliquer les données
    à l'intérieur de ceux ci :
    Code :
    1
    2
    3
    4
    5
    6
    7
        private double initialX = 0.0d ; 
        private double initialY = 0.0d; 
        private double initialZ = 0.0d; 
        private double x = 0.0d ; 
        private double y = 0.0d; 
        private double z = 0.0d;
    Encore une duplication de données, avec incohérence à prévoir.
    Pour recouvrir ta crotte, tu ajoutes également 2 méthodes
    ( 2 !! ) pour restaurer discrètement les données en cours de calcul.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
        public void resetInitialValues(){ 
          initValues(this.initialX, this.initialY, this.initialZ); 
        } 
    
        public Point3 getInitialValue(){ 
          this.resetInitialValues(); 
          return this; 
        }
    L'accès à un point devient donc:
    Code :
    1
    2
    p2 = this.arrayOfPoints[i].getInitialValue();
    au lieu de :
    Code :
    1
    2
    p2 = this.arrayOfPoints[i];
    Bien sur, à l'issue du dernier calcul, on ressort de aire() avec
    un polygone vérolé. L'utilisateur à l'aire, mais plus son polygone,
    il doit être content.

    Il y a en C++ un mot clé const qui dit qu'une méthode s'engage à ne pas
    modifier son objet support. Voir mon code.
    Code :
    1
    2
    double polygone::aire() const
    OK, ce n'est pas assez bon pour Java mais ça t'aurait
    rendu service ici.


    Au moins une autre "optimisation" est nuisible dans ton programme :
    tu as sorti l'appel au duplicateur de point ( dup() ) de la méthode
    Polygone.addPoint3(). Cette duplication avait pour but d'éviter à
    l'utilisateur imprévoyant de se retrouver avec un polygone dont tous
    les éléments pointent sur un seul et même point.

    Problème typique de l'utilisation de pointeurs.
    Non allez je rigole ! Il n'y a pas de pointeur en Java.

    Comme cette tentative d'éviter les variables intermédiaires
    à foiré comme les précédentes, tu as remis l'appel
    à dup() (rebaptisé dub() ) dans l'appel de addPoint3() .

    Tu n'as donc rien gagné, mais en plus, le premier utilisateur naif
    de Polygone va se retrouver avec un bug lorqu'il utilisera addPoint3()
    en oubliant de dupliquer "a la main".



    Conclusion:
    ===========

    A propos des performances.
    -------------------------
    Les performances que tu exhibes n'ont aucune valeur puisque le programme
    n'exécute plus les mêmes opérations. Je me suis abstenu de ce genre
    de manipulation (pourtant il m'aurait été très simple de fourguer
    un opérateur += à la place de + et autres raccourcis).
    Non seulement ton approche n'est pas honnête, mais en plus tes sabots
    sont particulièrement bruyants.

    Au passage, la taille des données à augmenté (plus de X 2)
    et le nombre de méthodes a aussi augmenté.

    A propos du style
    -----------------
    La modélisation objet en a pris un sale coup.
    Un vecteur dans l'espace a trois composantes, et je ne vois
    par pourquoi je devrais déclarer six doubles.
    Même remarque pour la structure de données redondante et potentiellement
    incohérente de polygone.

    La programmation par objet permet théoriquement de rester proche
    du problème (en manipulant les concepts qui interviennent dans celui-ci)
    Or ton code est au ras de l'implémentation, basé sur des bidouilles
    qui feraient redoubler un étudiant de 1ère année de fac.

    A propos de Java
    ----------------
    Je suis heureux que ce code m'offre l'occasion de montrer ce qui se
    passe lorsqu'un langage est insuffisant pour l'usage auquel on l'emploie.
    On passe des constructions de haut niveau à des constructions
    de bas niveau, par exemple ici on abandonne les Vector au profit des
    tableaux et les Point3 au profit d'une espèce de cache de 3 doubles
    qui évite d'avoir à créer un Point3 supplémentaire.

    Relisez les post antérieurs de Gregory Picavet et vous verrez
    qu'il préconise des techniques d'optimisation analogues: recopier
    les données dans des SD de bas niveau pour les manipuler.



    Le message émis par vos deux contributions est clair.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    Pour écrire des programmes Java dont la vitesse soit acceptable vous devez:
    
    1) Utiliser le moins d'objet possible ;
    2) Utiliser les tableaux de préférence aux conteneurs évolués ;
    3) Faire attention à ne pas saturer le GC (lu également dans une autre
    contribution) ;
    4) Vous prendre la tête pour imaginer les hacks les plus tordus.
    Il ne peut pas y avoir de démonstration plus éclatante des carences
    de ce langage si on l'utilise pour autre chose que de programmer des
    interfaces.

    Si j'avais balancé ça tout de go, on m'aurait traité de Charlot.

    Mainenant que c'est arrivé en direct devant vous, peut-être y croirez-vous.



    sur ma machine
    code ++gib : 4 points prennent 9 secondes à s'exécuter
    8 points prennent 25 secondes à s'exécuter
    mon code : 4 points prennent 2 secondes à s'exécuter
    8 points prennent 5 secondes à s'exécuter
    Bravo, ton programme hyper-hacké et buggé reste 3 fois plus lent
    qu'un programme rédigé proprement.
    D'autre part pour t'apprendre ce qu'est une méthode scientifique, évalue
    la précision relative d'une mesure de 2 secondes avec une résolution de
    1 seconde.

    Alors java n'est pas performant avec les objets??
    En luttant avec auttant de force pour les éliminer de ton programme,
    tu montres à l'évidence que
    Java n'est pas performant, SURTOUT avec les objets.
    Evidemment quand programme à la façon sauvage, on obtient des résultats médiocres...
    Ce sera le mot de la fin.

  18. #98
    Membre éprouvé
    Avatar de grishka
    Inscrit en
    janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 285
    Points : 470
    Points
    470

    Par défaut

    Le parcours d'un Vector avec Enumeration est plus rapide que celui d'un Arraylist avec Iterator (cf message précédent)

    En voila la preuve :
    v

    ArrayList dérive de AbstractList (comme LinkedList). Le code de l'itérateur est donc commun aux deux classes...

    code source de la classe interne AbstractList.Itr (itérateur):

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    	public boolean hasNext&#40;&#41; &#123;
    	    return cursor != size&#40;&#41;;
    	&#125;
    
    	public Object next&#40;&#41; &#123;
    	    try &#123;
    		Object next = get&#40;cursor&#41;;
    		checkForComodification&#40;&#41;;
    		lastRet = cursor++;
    		return next;
    	    &#125; catch&#40;IndexOutOfBoundsException e&#41; &#123;
    		checkForComodification&#40;&#41;;
    		throw new NoSuchElementException&#40;&#41;;
    	    &#125;
    	&#125;
    *hasNext() fait un appel polymorphique à size() de la classe dérivée ArrayList
    *next() vérifie les modifs concurrentes externe à l'iterateur et fait un appel polymorphique à get()

    code source de Vector :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
      public Enumeration elements() {
    	return new Enumeration() {
    	    int count = 0;
    
    	    public boolean hasMoreElements() {
    		return count < elementCount;
    	    }
    
    	    public Object nextElement() {
    		synchronized (Vector.this) {
    		    if (count < elementCount) {
    			return elementData[count++];
    		    }
    		}
    		throw new NoSuchElementException("Vector Enumeration");
    	    }
    	};
        }
    *aucun appel polymorphique car implémentation à la volée.
    *aucune verif sur les modifs externe à l'enumération pour un même thread
    *synchronization seulement sur nextElement car on y modifie count.

    Par contre les méthodes get et set et d'accés en général sont plus rapides sur ArrayList (l'appel polymorphique est plus rapide qu'une synchro...)

    La méthode add est peut-être plus rapide sur Vector si on fait des ajouts répétés (genre 1000000...)
    Le cout amorti d'un ajout est O(1) pour les deux conteneurs, mais est atteint plus rapidement pour un Vector car il double la capacité à chaque réallocation, tandis qu'un ArrayList augmente de 50%. Mais on peut fixer le pourcentage dans le constructeur de Vector. Plus on le baisse, plus on se rapproche de O(n)...

    Si on voit le Vector comme une List, par contre, il devient plus lent qu'un ArrayList. (on utilise les mêmes méthodes que AbstractList)

    bref, l'intérêt d'un Vector est faible car il est possible de créer une version synchronisée pour tous les conteneurs. Le seul intérêt est Enumération par rapport à Iterator, mais pour plus de rapidité il vaut mieux utiliser get si on utilise ArrayList (un gain de 100%!!). Sinon, si on travaille sur une collection sans savoir ce que c'est réellement, la y'a pas le choix.

  19. #99
    Membre du Club
    Inscrit en
    janvier 2003
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : janvier 2003
    Messages : 26
    Points : 65
    Points
    65

    Par défaut

    Citation Envoyé par Grégory Picavet
    Une exception devrait se produire seulement si le nombre de token numérique avant chaque ';' n'est pas un multiple de trois.

    pour eviter de terminer une boucle par une exception , un truc dans ce style :

    while( stream.hasMorePolygons() ) {
    }
    Je suis d'accord avec toi. ;-)

    FileInputStream +
    InputSteamReader +
    FormattedIStream
    Pourquoi le InputStreamReader ici?
    Parceque:
    Code :
    1
    2
    3
    4
    5
    StreamTokenizer&#40;InputStream is&#41; 
              Deprecated. As of JDK version 1.1, the preferred way to tokenize an input stream is to convert it into a character stream, for example&#58; 
       Reader r = new BufferedReader&#40;new InputStreamReader&#40;is&#41;&#41;;
       StreamTokenizer st = new StreamTokenizer&#40;r&#41;;

    Il est tellement "simple" que toute la complexité est reportée
    sur les bibliothèques
    Le design pattern Decorateur permet d'ajouter dynamiquement des fonctionnalités à une hiérarchie de classe. c'est une approche différente du c++.
    avantages/inconvénients :
    Comme avec les Lego(tm), tu peux interconnecter plusieurs décorations avec une classe de départ pour obtenir toute les combinaisons possibles moyennant très peu de classes (classes de départ, et classes de décoration). En héritage simple, cela aurait donné une progression exponentielle du nombre de classe pour chaque nouvelle fonctionnalité. De plus pour le nommage des classes, ca aurait été compliqué.
    L'inconvénient de cette flexibité est un code plus lourd.
    J'ai bien compris, c'est flexible mais lourd.
    J'ai aussi compris que l'héritage simple a tendance à
    génèrer un grand nombre de classes car on ne peut hériter de plusieurs
    fonctionnalités en 1 seul niveau.

    Pour en revenir a FormattedIStream :
    Pas d'autre moyen de lire des données dans un fichier texte de structure simple ?

  20. #100
    Membre émérite

    Inscrit en
    mars 2002
    Messages
    30
    Détails du profil
    Informations forums :
    Inscription : mars 2002
    Messages : 30
    Points : 913
    Points
    913

    Par défaut

    Merci ++gib, tu m'as ouvert les yeux, Java est un mauvais langage, une pâle copie du C++... Le tout puissant C++ a definitivement remporté la partie, d'ailleur je vais desuite corrigé mon pseudo :
    ++Clément Cunin
    Incrémenté de la sorte, je cours préché la bonne parole :

    - La programmation en environnement protégé n'apporte rien, La stabilité des application Java basé sur cet environnement protégé n'est que du vent.
    - Les milliers de programmeurs Java sont tous des cons qui n'y comprenne rien.
    - La technologie dotNet qui trouve ces fondement dans Java n'a pas plus d'interet...
    - Programmeur rangez vos servlets, rangez vos JSP, le retoure à la programmation des CGI est une nécessité, retrouvez toute la puissance des l'operateurs "<<" et ">>" pour géré vos flux.
    - Scientifique, industrielle reprogrammez vos applications en C++, c'est certe couteux, mais pensez à tous ces processeurs qui souffre d'être utilisé à presque 10% alors que le même programme C++ permeterait une utilisation de seulement 5% du processeur. ( C'est très important, un processeur qui travail moins, consomme moins, donc lute contre l'effet de serre...)

    Vive le Segmentation fault, vive le coreDump, vive le C++...
    Ce débat me fatigue, @+

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •