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

Langage Java Discussion :

Faire la moyenne d'un flux de données dans une classe dédiée.


Sujet :

Langage Java

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 4
    Par défaut Faire la moyenne d'un flux de données dans une classe dédiée.
    Bonjour,
    Le titre est compliqué, mais ce que je cherche à faire est simple. Je cherche à utiliser une classe pour traiter des données provenant d'un capteur de type Kinect : je reçois, pour simplifier, un flux de floats, et je cherche à faire la moyenne de ces données par paquets de 3.

    Le code qui m'est venu à l'esprit est le suivant :
    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
    public class MathTools {
     
    private static float moy = 0f;
    private static float calc = 0f;
    private static int indice = 0;
     
    public MathTools() {
    }
     
    public static float moyenne(float valeur) {
        indice++;
        calc += valeur;
        if (indice == 3) {
            moy = calc/3.0;
            ind = 0;
            calc = 0f;
        }
        return moy;
    }
    }
    L'idée est d'utiliser la fonction MathTools.moyenne(valeur) pour renvoyer un calcul de la moyenne de mon flux de données tous les 3 chiffres qui lui parviennent :
    1 --> MathTools.moyenne(1) = 0
    2 --> MathTools.moyenne(2) = 0
    3 --> MathTools.moyenne(3) = (1 + 2 + 3)/3 = 2
    4 --> MathTools.moyenne(4) = 2
    5 --> MathTools.moyenne(5) = 2
    6 --> MathTools.moyenne(6) = (4 + 5 + 6)/3 = 5
    7 --> MathTools.moyenne(7) = 5
    8 --> MathTools.moyenne(8) = 5
    9 --> MathTools.moyenne(9) = (7 + 8 + 9)/3 = 8
    etc.

    La fonction est correcte et fonctionne, mais le problème que je rencontre est le suivant : comme ma fonction est statique, je ne peux PAS l'utiliser plusieurs fois pour plusieurs flux de valeurs. Puisque les variables sont les identiques (static), deux versions de cette fonction vont interagir et le résultat sera faussé.

    La seconde idée qui m'est venue est d'utiliser une fonction et des variables NON statiques, mais dans ce cas, je doit définir autant d'instances de cette classe qu'il y a de fonction moyenne(), ce qui n'est vraiment pas pratique !!! J'aurais voulu utiliser des fonctions comme celles de la classe java.lang.Math par exemple (elles sont toutes statiques). La différence entre ces fonctions et la mienne est que je suis obligé (sauf erreur de ma part) d'utiliser des variables extérieures à ma fonction pour faire le calcul (indice, calc, moy).

    Auriez-vous une idée pour faire ce genre de calcul dans une classe ? J'avoue que je sèche un peu...

    Cordialement,

    RP.

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    Je ne comprend pas trop ce qui te pose problème avec l'utilisation d'instances...
    Au contraire c'est pile poil ce qu'il faut faire.

    Les champs static modifiables posent toujours ce genre de problème...



    Sinon c'est voulu ces sauts tous les 3 valeurs ?
    Ne serait-il pas préférable d'avoir une progression continue :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    1 --> MathTools.moyenne(1) = 1/3 = 0.33
    2 --> MathTools.moyenne(2) = (1 + 2)/3 = 1 
    3 --> MathTools.moyenne(3) = (1 + 2 + 3)/3 = 2
    4 --> MathTools.moyenne(4) = (2 + 3 + 4)/3 = 3
    5 --> MathTools.moyenne(5) = (3 + 4 + 5)/3 = 4
    6 --> MathTools.moyenne(6) = (4 + 5 + 6)/3 = 5
    7 --> MathTools.moyenne(7) = (5 + 6 + 7)/3 = 6
    8 --> MathTools.moyenne(8) = (6 + 7 + 8)/3 = 7
    9 --> MathTools.moyenne(9) = (7 + 8 + 9)/3 = 8

    a++

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 4
    Par défaut
    Merci de ta réponse.

    Oui les sauts de valeurs ne me dérangent pas. Mais j'ai du mal me faire comprendre... Si je cherche à faire la moyenne de chacun de 3 flux de données provenant, par exemple, des positions x, y et z d'une Kinect, je ne peux pas utiliser ma fonction de la façon suivante :

    float positionX, positionY, positionZ;

    ...

    positionX = MathTools.moyenne(valeursX);
    positionY = MathTools.moyenne(valeursY);
    positionZ = MathTools.moyenne(valeursZ);

    System.out.println ("Positions = " + positionX + ", " + positionY + ", " + positionZ);

    Cela ne marche pas car chaque moyenne utilise les mêmes variables (puisqu'elles sont statiques). C'est ça mon problème : je cherche à faire une fonction dans une classe qui renvoie le bon calcul.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 4
    Par défaut
    Les instances me gênent car il faut créer UNE instance par fonction moyenne()...

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Et alors ? tu veux calculer 3 moyennes donc tu crées 3 instances.
    Dès que tu dois gérer un état je ne vois pas comment tu pourrais passer outre, ni en quoi cela pose problème...


    a++

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 4
    Par défaut
    Disons que je cherchais une solution plus pratique que de créer autant d'instances que de fonctions !

    Quand j'utilise plusieurs sin(x) dans une fonction, je ne crée pas autant d'instance de java.lang.Math que de sinus... Dans mon cas de figure, c'est un peu différent car le calcul de la fonction est fait en mémorisant 2 valeurs précédentes pour calculer la moyenne sur la 3è valeur, mais si, pour reprendre l'exemple de Kinect qui restitue une dizaine de flux de données pour chaque point du squelette, je dois créer dix instances de ma classe, cela ne me semble pas optimum...

  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Math.sin() n'a pas d'état à gérer, et est totalement autonome... donc il n'y a pas d'intérêt à créer une instance pour cela.


    Sinon je ne vois pas ce qui n'est pas "optimum" dans le fait de créer 10 instances.


    Maintenant si tu veux à tout prix utiliser une méthode static, la seule solution c'est de dupliquer ton code 10 fois.
    Mais c'est une très mauvaise idée... et ce ne sera pas plus "optimum" pour autant (au lieu d'avoir 10 instances tu auras 10 fois plus de variables static), sans compter la duplication de code.
    Et je t'explique même pas le jour où tu va devoir gérer un très grand nombre de moyenne...


    a++

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    Je crois que tu parts mal sur le design de ta méthode / fonctionnalité dès le départ. Déjà tu n'obtiens une valeur que toutes les 3 valeurs -> Il serait plus pratique pour l'appelant de le savoir au moment opportun plutôt que de sortir des trucs bidon. Une solution serait un callback qui reçois chaque moyenne et en fait quelque chose. Ainis ce qui nourris ta moyenne et ce qui l'utilise sont découplés. Et si demain tu veux une moyenne toutes les 5 valeurs tu ne dois pas revoir tout ton code.


    Une implémentation simple serait par exemple:
    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
    public class MeanBuilder {
        int count = 0;
        int total = 0;
        Consumer<Integer> result;
     
        private MeanBuilder(Consumer<Integer> result) {
          this.result = result;
        }
     
        MeanBuilder push(int t) {
          total += t;
          count++;
          if (count == 3) {
            count = 0;
            result.accept(total / 3);
            total = 0;
          }
          return this;
        }
     
        public static MeanBuilder build(Consumer<Integer> result) {
          return new MeanBuilder(result);
        }
      }
    Qui permet par exemple cette utilisation toute simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      public static void main(String[] args) {
        MeanBuilder.build(System.out::println)
            .push(1)
            .push(2)
            .push(3)
            .push(4)
            .push(5)
            .push(6);
      }
    Tant qu'à utiliser un Consumer, autant aussi utiliser ça a la sortie, histoire de pouvoir après rentrer ça dans l'api stream de java au besoin.
    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
        public static IntConsumer mean(IntConsumer result) {
          return new IntConsumer() {
            int count = 0;
            int total = 0;
     
            @Override
            public void accept(int t) {
     
              total += t;
              count++;
              if (count == 3) {
                count = 0;
                result.accept(total / 3);
                total = 0;
              }
            }
     
          };
        }
    Par contre du coup on ne peut pas chainer les appels, il faut tout écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    IntConsumer consumer = MeanBuilder.mean(System.out::println);
        consumer.accept(1);
        consumer.accept(2);
        consumer.accept(3);
        consumer.accept(4);
        consumer.accept(5);
        consumer.accept(6);
     
       // ou 
     
     
        IntStream dataStream = Arrays.stream(new int[] { 1, 2, 3, 4, 5, 6 });
        dataStream.forEach(MeanBuilder.mean(System.out::println));
    On peut inverser la logique et travailler avec un supplier pour "pomper" les moyennes quand on en a besoin si tu préfère

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        public static IntSupplier mean(IntSupplier producer) {
          return new IntSupplier() {
            @Override
            public int getAsInt() {
              // TODO Auto-generated method stub
              return (producer.getAsInt() + producer.getAsInt() + producer.getAsInt()) / 3;
            }
          };
        }
    on utiliserait comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        IntSupplier supplier = () -> new Random().nextInt(1000); // a générer à partir du Kinet
        supplier = MeanBuilder.mean(supplier);
        System.out.println("prochaine valeur de moyenne: "+supplier.getAsInt());
    Enfin, on peut utiliser directement un Stream histoire de faire d'autres manipulation, mise en collection, etc.

    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
     
        public static IntStream mean(IntStream dataStream) {
          return dataStream.map(new IntUnaryOperator() { //renvoie une valeur spéciale lorsqu'on a pas 3 items, sinon renvoie la moyenne
            int count = 0;
            int total = 0;
     
            @Override
            public int applyAsInt(int t) {
              total += t;
              count++;
              if (count == 3) {
                int result = total / 3;
                count = 0;
                total = 0;
                return result;
              } else {
                return Integer.MAX_VALUE;
              }
            }
          })
          .filter((i) -> i != Integer.MAX_VALUE); // éjecte du stream les valeurs spéciales, ni vu ni connu
        }
    Qu'on utiliserait comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        IntStream dataStream = Arrays.stream(new int[] { 1, 2, 3, 4, 5, 6 });
        MeanBuilder.mean(dataStream).forEach(System.out::println);
    Et bien sur on peux faire des variantes avec double, float, BigDecimal etc

    Bref ce ne sont pas les solution élégantes qui manquent, reste à savoir comment tu as besoin d'utiliser ton api

Discussions similaires

  1. Récupération d'une donnée dans une classe
    Par Alice23 dans le forum Windows Phone
    Réponses: 26
    Dernier message: 07/01/2012, 12h01
  2. [JpGraph] Faire le tableau array($abc) à partir des données d'une table
    Par medhan dans le forum Bibliothèques et frameworks
    Réponses: 7
    Dernier message: 14/11/2008, 11h35
  3. Comment faire apparaitre des données dans une listbox
    Par nuans dans le forum Interfaces Graphiques
    Réponses: 3
    Dernier message: 14/05/2007, 15h04
  4. [MySQL] Php, je ne comprends pas comment faire pour introduire des données dans une table
    Par Liondd dans le forum PHP & Base de données
    Réponses: 23
    Dernier message: 14/12/2006, 12h53
  5. Réponses: 2
    Dernier message: 28/10/2005, 12h52

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