IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

opération sur les éléments de tableaux


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 46
    Par défaut opération sur les éléments de tableaux
    Bonjour,

    Jusqu'à présent j'ai codé en Matlab mes modèles de simulations de fluide. Jusqu'à présent tout le monde me disait que je devrais utiliser c++ (ou fortran) c'est plus rapide.
    Aujourd'hui je me suis dit qu'on allait essayer... Je n'arrive pas à la même conclusion, j'aimerai donc un peu de vos lumières (je suis débutant en c++).

    En Matlab il faut à mon PC 0.176 secondes pour faire la somme élément à élément de deux matrices contenant 5000x5000 nombres aléatoires (double précision).
    En C++ il lui faut 1.46 (presque 10 fois plus lent)!

    Alors comme je débute en C++, je ne fais peut être pas les choses correctement. Je ne suis pas arrivé à trouver de bibliothèque qui me permette de faire des opérations à la volé entre 2 tableaux en c++ comme on peut le faire en Matlab. J'ai donc 2 boucles imbriquées... Bref, je vous met le code ci-dessous (les fonctions tic toc sont codés ailleurs, j'ai utilisé ça: http://www.cplusplus.com/reference/ctime/).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    #include "tic_toc.h"
     
    #include <iostream>
    #include <stdlib.h>
    #include <time.h>
     
     
    using namespace std;
     
     
    int main()
    {
     
    	int n(5000);
     
    	double* A = new double[n*n];
    	double* B = new double[n*n];
    	double* C = new double[n*n];
     
     
    	int i(0);
    	int j(0);
    	for (i = 0; i < n; i++)
    	{
    		for (j = 0; j < n; j++)
    		{
     
    			A[i*j] = float(rand() % 100000)/100000;
    			B[i*j] = float(rand() % 100000)/100000;
     
    		}
    	}
     
     
     
    	tic();
     
    	for (i = 0; i < n; i++)
    	{
    		for (j = 0; j < n; j++)
    		{
    			C[i*j] = A[i*j] + B[i*j];
    		}
    	}
     
    	toc();
     
    	delete[] A;
    	delete[] B;
    	delete[] C;
     
     
    	system("pause");
    	return 0;
    }

    J'ai quand même remarqué qu'en utilisant ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (i = 0; i < n*n; i++)
    	{
    		C[i] = A[i] + B[i];
    	}
    le temps de l'opération tombait 0.23 secondes.


    Pouvez vous me m'expliquer si bon benchmark est comparable, s'il y a d'autres moyens de faire en c++ (une librairie?) etc.
    NB: Je ne parallélise pas car mon Matlab s’exécute sur un cœur. A terme je compte bien passer en c++ pour pouvoir paralléliser mes modèles.


    Merci d'avance pour votre aide/explications.

  2. #2
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2013
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2013
    Messages : 114
    Billets dans le blog
    3
    Par défaut
    Bonjour,

    Ton calcul d'indice est étrange: ça ne devrait pas être i*n+j, ou quelque chose du genre?

    Sur le benchmark, ça parait un peu étonnant, tu lances une boucle qui contient 25 millions d'itérations, ça ne devrait pas prendre plus d'une seconde (même les 0,23 secondes pour la seconde version paraissent énormes, à moins que tu travailles sur une machine de musée). Peux tu regarder les paramètres de ton compilateur:
    - les optimisations sont activées?
    - tu n'es pas dans un mode de débogage qui vérifie chaque accès à chaque tableau?

    Francois

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 46
    Par défaut
    Hum en fait en matlab on peut faire un tableau de 5000x5000 sans soucis. En c++ je n'ai pas trouvé comment faire (je débute vraiment, avant le benchmark j'en étais à "Hello World"). J'ai pu faire des petit tableau, mais passé une limite (100x100) je me retrouve avec un stack overflow (pas la moindre idée d'où ça vient). Sur internet, j'ai cru comprendre qu'il fallait passer par un pointeur avec un constructeur et un destructeur... Mais que dans le process on ne pouvait plus que faire des tableaux à une dimension.
    Bon pour le moment l'important c'est qu'il y ait autant d'éléments dans un code que dans l'autre.

    Je ne travaille pas avec une pièce de musée ^_^ enfin je ne crois pas!
    Voilà ma config en quelques lignes:
    Proc i7 930 @2.8Ghz 8 threads
    RAM 6 Go
    Asus P6T6 WS.

    Concernant les paramètres du compilateur je vais chercher. Comme je débute, ça non plus je ne sais pas faire (vais apprendre et je reviens).

    Merci pour ta réponse en tout cas!

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Citation Envoyé par pingouin84k Voir le message
    Hum en fait en matlab on peut faire un tableau de 5000x5000 sans soucis. En c++ je n'ai pas trouvé comment faire
    Au moins 2 façons . Soit avec des malloc soit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        double A[5000][5000];
        memset(A, 0, 5000*5000*sizeof(double);
    Mais ici pas besoin de memset puisque tu fais une initialisation aléatoire

    Et pas besoin de free à la fin.

    Et l'autre truc, il me semble, c'est la précision. Si tu n'as pas besoin de précision, utilise des float au lieu de double.

    Édit: tu as oublié d’initialiser la graine documentation rand

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 46
    Par défaut
    Bonjour à tous et merci pour vos réponses!

    @JolyLoic, fcharton2
    Oui effectivement mon calcul d'indice était farfelu. Je n'y avais même pas fait attention (la fatigue ).
    En corrigeant i*j par i*n+j ça va plus vite, 0.25 seconde, c'est presque aussi rapide qu'avec une seule boucle.
    J'imagine que pour faire de la vectorisation de double, ce n'est pas vraiment à la portée d'un débutant...
    Étant donné que la parallélisation en c++ semble bien plus simple qu'en Matlab, j'ai bon espoir d'arriver à quelques chose de plus performant au final.

    Et comme je fais de la mécanique des fluides avec écoulement réactifs, oui j'ai de nombreux "très grands" tableaux. De manière générale avec Matlab j'avais typiquement des tableaux de 5.000 à 10.000 cellules. En passant en c++ avec de la parallélisation, j'ai bon espoir de pouvoir monter à 100.000 cellules sans trop impacter mon temps de calcul global.

    @foetus
    J'ai copié collé ton bout de code et je me retrouve avec Stack Overflow.

    @fcharton2
    J'utilise MS Visual C++ 2010 Express. J'ai cherché les options de compilation, pas trouvé. Donc je ne peux dire quels sont les options d'optimisation il y a. J'ai exécuté mon code alors qu'il y a écrit "Debug" dans le drop box "Configurations de solutions". En mode Release j’obtiens sensiblement le même résultat.

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par pingouin84k Voir le message
    @JolyLoic, fcharton2
    Oui effectivement mon calcul d'indice était farfelu. Je n'y avais même pas fait attention (la fatigue ).
    En corrigeant i*j par i*n+j ça va plus vite, 0.25 seconde, c'est presque aussi rapide qu'avec une seule boucle.
    Bien ce qu'il me semblait... C'est là qu'on voit l'intérêt du cache de mémoire du processeur. Après, si tu avais de plus petits tableaux, peut-être que l'écart entre la solution à 2 boucles et la solution à 1 boucle serait plus sensible.
    Citation Envoyé par pingouin84k Voir le message
    J'imagine que pour faire de la vectorisation de double, ce n'est pas vraiment à la portée d'un débutant...
    Ce n'est pas non plus totalement impossible pour des calculs simples comme ça, là où c'est moins simple, c'est quand la complexité des calculs augmente, ou quand tu veux faire des solutions génériques... Mais de toute manière, une bonne bibliothèque est là pour que tu n'aies pas à te poser ce genre de questions bas niveau, et que tu puisses te concentrer sur ta valeur ajoutée.
    Citation Envoyé par pingouin84k Voir le message
    Étant donné que la parallélisation en c++ semble bien plus simple qu'en Matlab, j'ai bon espoir d'arriver à quelques chose de plus performant au final.
    Vectorisation et parallélisation ne sont pas concurrents, mais complémentaires.
    Citation Envoyé par pingouin84k Voir le message
    @fcharton2
    J'utilise MS Visual C++ 2010 Express. J'ai cherché les options de compilation, pas trouvé. Donc je ne peux dire quels sont les options d'optimisation il y a. J'ai exécuté mon code alors qu'il y a écrit "Debug" dans le drop box "Configurations de solutions". En mode Release j’obtiens sensiblement le même résultat.
    Par défaut, la configuration Release contient les options d'optimisation classiques qui marchent bien pour avoir du code rapide dans le cas général. Donc, globalement, si tu travailles en Release, pas en Debug, tu n'es pas loin des performances optimales du compilateur.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2013
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2013
    Messages : 114
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par pingouin84k Voir le message
    Hum en fait en matlab on peut faire un tableau de 5000x5000 sans soucis. En c++ je n'ai pas trouvé comment faire (je débute vraiment, avant le benchmark j'en étais à "Hello World"). J'ai pu faire des petit tableau, mais passé une limite (100x100) je me retrouve avec un stack overflow (pas la moindre idée d'où ça vient). Sur internet, j'ai cru comprendre qu'il fallait passer par un pointeur avec un constructeur et un destructeur... Mais que dans le process on ne pouvait plus que faire des tableaux à une dimension.
    En gros, en C++, il faut allouer l'espace dont tu as besoin pour tes tableaux. Ce que tu déclares dans la pile (avec des choses comme double montableau[100][100]) est limité à la taille de la pile, d'où le stack overflow

    Pour l'allocation, ce que tu fais (avec new) est globalement correct. Tu peux aussi utiliser un vector<double>, (vector<double> v(n*n,0.0); ). Et tu peux aussi fabriquer des tableaux à deux dimensions, soit comme des vector< vector<double> >, soit comme des double **, dont tu réalloues toutes les lignes.

    A mon avis, ton problème vient d'ailleurs. Il n'y a pas de raison que la copie mette autant de temps. Donc regarde la configuration de ton compilateur. C'est un bon investissement, de toutes façons.

    Francois

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par fcharton2 Voir le message
    Pour l'allocation, ce que tu fais (avec new) est globalement correct. Tu peux aussi utiliser un vector<double>, (vector<double> v(n*n,0.0); ). Et tu peux aussi fabriquer des tableaux à deux dimensions, soit comme des vector< vector<double> >, soit comme des double **, dont tu réalloues toutes les lignes.
    C'est généralement une mauvaise idée (sauf si vraiment très grands tableaux), ça on remplace une allocation mémoire par plein de plus petites, ce qui est coûteux...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par pingouin84k Voir le message

    J'ai quand même remarqué qu'en utilisant ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (i = 0; i < n*n; i++)
    	{
    		C[i] = A[i] + B[i];
    	}
    le temps de l'opération tombait 0.23 secondes.
    Cette seconde façon de faire est bien meilleurs, et en plus, elle n'a pas d’erreur dans le calcul des indices Je serais curieux de savoir combien de temps prend la première façon de faire corrigée (qui du coup va bénéficier du cache mémoire, alors que ta version avec les indices farfelus n'en bénéficie pas).

    Mais si tu veux rivaliser avec Matlab, il te faut probablement tirer parti de la vectorisation du ton processeur (le fait qu'il peut simultanément faire des additions de plusieurs double d'un coup, sans pour autant programmer en parallèle). Certains compilateurs arrivent dans des cas simples à utiliser ces instructions sur des cas simples, je ne sais pas si ça a été le cas ici. Peut-être en regardant le code généré ?

    Sinon, pour ce genre de choses, j’utiliserais une bibliothèque existante, comme par exemple eigen ou nt² (je ne peux juger de la qualité, ça fait longtemps que je n'ai pas fait de calcul scientifique dans mon boulot, mais les deux ont l'air à jour et maintenues). Lire par exemple http://eigen.tuxfamily.org/dox/Topic...enExample.html pour une idée de ce qui peut se passer dans ce genre de bibliothèques.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. opérations sur les tableaux
    Par marco62118 dans le forum Langage
    Réponses: 2
    Dernier message: 30/11/2009, 16h52
  2. [OpenGL/C++] Opérations sur les Textures
    Par Bob.Killer dans le forum OpenGL
    Réponses: 6
    Dernier message: 10/08/2005, 10h27
  3. Opérations sur les matrices...
    Par aokiseiichiro dans le forum C
    Réponses: 32
    Dernier message: 28/07/2005, 17h10
  4. opérations sur les bits d'un byte
    Par petitours dans le forum C++Builder
    Réponses: 4
    Dernier message: 10/02/2004, 20h42
  5. opérations sur les dates
    Par coucoucmoi dans le forum Débuter
    Réponses: 2
    Dernier message: 12/08/2003, 11h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo