Idée de concours : Optimisation de code

Ok je vais essayer de lancer ça entre les fêtes et on verra bien comment ça se passe ... :smiley: !

Les fêtes sont passées, et pas de suite...
Alors je vous propose un sujet :

Comment extraire des nombres d'un tableau de caractères ?
Supposons un tableau de caractères contenant des nombres perdus à l'intérieur, aussi bien des entiers que des décimaux, positifs ou négatifs, en nombre quelconque. Construire une fonction qui extrait ces nombres et les mets dans deux tableaux (int et float).

Exemple : la fonction extractNumbers renseigne les tableaux (variables globales) entiers et decimaux (taille limitée à 10 ici mais ce n'est peut-être pas nécessaire). Elle sauve le nombre d'entiers et de décimaux trouvés dans les variables nbEntiers et nbDecimaux.

char message[] = "abc123def-456gh1.2345!*_()-9.8765yz";
int entiers [10] = {0};
floats decimaux[10] = {0};
byte nbEntiers;
byte nbDecimaux;
extractNumbers (message, strlen(message));

Qui veut s'y lancer ? L'objectif serait de respecter certains critères :

  • Fonction facile à comprendre
  • Fonction pas trop longue
  • Programmation "élégante" (je vous laisse décider de ce que ça veut dire)

On rajoute peut être une contrainte sur la taille Max des nombres ?

-> Des int32_t ou des double au sens Arduino Uno (4 octets)

Sinon faut gérer aussi le nombre de dépassement de représentation

Pas de souci, chacun le fait comme il l'entend : je n'ai pas forcément la connaissance permettant de bien border le problème. C'est le type d'application qui peut fournir cette réponse.
L'idée est bien sûr de fournir des fonctions qui soient utilisables par chacun lorsqu'on en a besoin. J'ai proposé celui-ci car je viens d'en faire un plus simple pour un membre du forum US, et j'ai vu que ce n'est pas forcément facile à faire. Mais on peut en avoir besoin si on veut parser des entrées clavier (console) ou des réponses html, ou autres( certains capteurs peuvent renvoyer ce genre de résultat).

Par contre, si on continue sur cet exercice, peut-être faudrait-il en faire un sujet autonome ?

A mon avis si on veux faire un concours, il faut être précis dans la spécification fonctionnelle. Savoir écrire ou savoir lire un cahier des charges c'est la base des compétences nécessaires pour un bon développeur.

Par exemple un nombre flottant peut être représenté en notation scientifique: 123.345e-12 ou un entier peut être gigantesque 123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789. Que doit faire le code ?

Bien sûr ce genre de question s'est déjà posée il y a bien longtemps et l'approche standard en C ou C++ serait d'utiliser errno pour reporter une erreur ERANGE et de retourner le plus petit ou plus grand nombre représentable

de même l'approche standard pour la représentation d'un nombre serait de se rapprocher de ce que fait stdlib.h par exemple pour strtod() ou strtol()

leur définition de la lecture d'un nombre entier dans une certaine base est

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes as many characters as possible that are valid following a syntax that depends on the base parameter, and interprets them as a numerical value. Finally, a pointer to the first character following the integer representation in str is stored in the object pointed by endptr.

If the value of base is zero, the syntax expected is similar to that of integer constants, which is formed by a succession of:
An optional sign character (+ or -)
An optional prefix indicating octal or hexadecimal base ("0" or "0x"/"0X" respectively)
A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present

If the base value is between 2 and 36, the format expected for the integral number is a succession of any of the valid digits and/or letters needed to represent integers of the specified radix (starting from '0' and up to 'z'/'Z' for radix 36). The sequence may optionally be preceded by a sign (either + or -) and, if base is 16, an optional "0x" or "0X" prefix.

If the first sequence of non-whitespace characters in str is not a valid integral number as defined above, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

de même pour un nombre décimal:

A valid floating point number for strtod using the "C" locale is formed by an optional sign character (+ or -), followed by a sequence of digits, optionally containing a decimal-point character (.), optionally followed by an exponent part (an e or E character followed by an optional sign and a sequence of digits).

Je comprends. Il faut éviter de trop complexifier le problème sous peine de voir tout le monde fuir le "concours".

On pourrait se restreindre à parser des long (donc des entiers entre -2147483648 et 2147483647) et des floats sans la notation scientifique (par exemple 12345.67), éventuellement précédés par un '+' ou un '-' (ou rien) ?

De même, pour les entiers, on peut en rester à des représentations décimales, sauf si la prise en compte du binaire et/ou de l'hexadécimal n'augmente pas la complexité d'écriture de la fonction.

Bon. On fait quelque chose ou on laisse tomber ? Bruno14200... Es tu là ?

Proposition de cahier des charges:

écrire la fonction bool extraireNombres(const char * entree, int16_t * tableauEntiers, size_t& nbEntiers, float * tableauDecimaux, size_t& nbDecimaux, const char separateurDecimal) qui analyse la c-string (tableau de caractères terminée par un caractère NULL '\0') entree pour extraire et ranger dans les tableaux tableauEntiers et tableauDecimaux respectivement les nombres entiers et décimaux acceptables trouvés lors de l'analyse. Le nombre d'éléments trouvés sera à reporter respectivement dans nbEntiers et nbDecimaux.

On a le droit d'utiliser les fonctions c standard de stdlib.h ou string.h lors de l'analyse.

la c-string entree ne peut pas contenir plus de 10 nombres au total.

Les entiers acceptables sont les short aussi connus sous le type formel int16_t, donc entre -32768 to 32767, représentés en ASCII et base 10. Un seul signe - en début de séquence de chiffres est traité (par exemple aaa--[color=green]-12[/color]bbb sera reconnu comme [color=green]-12[/color]). Le caractère + dénote un entier positif (qui est le défaut), de même un seul plus en début de nombre. Si l'entier reconnu est en dehors des bornes autorisées alors l'intégralité de la séquence numérique est consommée par l'analyseur, la fonction reportera une erreur ERANGE dans errno pour et retournera le plus petit ou plus grand nombre représentable en fonction du sens de dépassement (par exemple si l'entier est -32769 alors on stocke dans le tableau -32768 et on met le errno sur ERANGE. Si la chaine est aaaaa[color=green]-3276900000000000000[/color]bbbb l'intégralité de la séquence -3276900000000000000 est consommée par l'analyseur et on continue à lire à partir du b). on peut avoir autant de 0 en début de nombre que l'on veut. 0000001 sera reconnu comme 1.

Les nombre décimaux sont les float en Single Precision sur 32 bits, donc entre -3.4e38 .. 3.4e38. la représentation autorisée est proche de celle que l'on a prise pour les entiers, pas de notation scientifique. Un nombre décimal contient donc un entier, suivi obligatoirement d'un seul symbole séparateur entre la partie entière et la partie décimale suivi d'un autre entier qui comportera au moins 1 chiffre valide. Par exemple aaa25,bbb ne sera pas reconnu comme un nombre décimal et donner juste un entier 25. mais aaa25,0bbb reconnaitra le nombre décimal 25,0

Le séparateur separateurDecimal est optionnel dans l'appel de la fonction. Il dénote quel symbole (de type char) est utilisé pour représenter un nombre décimal (les anglo-saxons et la programmation utilisent le point '.' mais en France on utilise la virgule ',' - d'autres symboles non numérique sont acceptables. Un chiffre passé comme séparateur devra faire que la fonction retourne immédiatement en revoyant false.)

Par défaut la fonction prendra la virgule française comme séparateur s'il n'est pas précisé lors de l'appel.

la fonction retourne true si elle a pu s'exécuter correctement, false si une incompatibilité a été détectée (y compris de représentation de nombre).

Donc par exemple -az---a//+[color=green]0123.45[/color]-----azlkkma[color=green]678,900[/color]blabla doit identifier comme entiers 123 et 45 et comme décimal 678,900 si le separateurDecimal n'est pas précisé (on prend alors la ',') mais si on précise que c'est '.' alors il faudra extraire en décimal 123.45 et en entiers 678 ainsi que 900

Critères d'évaluation dans l'ordre d'importance:

  • résultat correct
  • respect du cahier des charges
  • vitesse d'exécution de la fonction telle que calculé avec un appel à micros() avant la fonction et en sortie de fonction (avec interdiction de toucher aux interruptions ni au timer contrôlant micros())
  • impact sur l'utilisation de la mémoire (nombre d'octets nécessaires au bon déroulement de la fonction en dehors des paramètres).

tapé un peu vite, des avis ?

C'est très complet, mais un brin complexe. Notamment l'histoire des choses d'erreur.

Pour s'assurer du résultat correct, on peut fournir un jeu de cas tests.

OK pour simplifier.

On peut dire qu'un nombre qui ne rentre pas sera représenté par le nombre min ou max représentable, sans gérer d'erreurs par exemple.

je vous laisse virer ce que vous voulez.

Pas facile pour moi ce week-end, je n'ai que mon portable.

Mais j'aurais aussi aimé voir d'autres personnes s'intéresser à ce "concours" et son cdc pour s'assurer qu'il aura un minimum de participants...

laissons un peu de temps au bar de s'activer :slight_smile:

Je suis toujours présent :wink: .

Concernant ton exemple, J-M-L , j'envisageais plus "accessible" ..j'ai peur que ça effraie les débutants .

Biensur le but est de progresser donc le niveau ira en augmentant .

C'est dommage qu'on ne puisse pas faire de sondages sur ce forum .
Ca permettrait de voter pour son programme "préféré" de manière "démocratique" et sans jury .

BrUnO14200:
Concernant ton exemple, J-M-L , j'envisageais plus "accessible" ..j'ai peur que ça effraie les débutants .

j'ai juste documenté la proposition de @lesept. Pas de soucis pour faire plus simple. On pourrait dire par exemple extraire et classer des entiers uint8_t qui seraient dans la chaîne de caractères par ordre croissant ?

Je reprends le cahier des charges de J-M-L, en essayant de le simplifier. J'ajoute aussi quelques cas tests.

Proposition de cahier des charges:

Ecrire la fonction
bool extraireNombres(const char * entree, int16_t * tableauEntiers, size_t& nbEntiers, float * tableauDecimaux, size_t& nbDecimaux)
qui analyse la c-string (tableau de caractères terminée par un caractère NULL '\0') entree pour extraire et ranger dans les tableaux tableauEntiers et tableauDecimaux respectivement les nombres entiers et décimaux acceptables trouvés lors de l'analyse. Le nombre d'éléments trouvés sera à reporter respectivement dans nbEntiers et nbDecimaux.

On a le droit d'utiliser les fonctions c standard de stdlib.h ou string.h lors de l'analyse.

La c-string entree ne peut pas contenir plus de 10 nombres de chaque catégorie.

Les entiers acceptables sont les short aussi connus sous le type formel int16_t, donc entre -32768 to 32767, représentés en ASCII et base 10. Un seul signe - en début de séquence de chiffres est traité (par exemple aaa---12bbb sera reconnu comme -12). Si l'entier reconnu est en dehors des bornes autorisées alors la fonction renvoie false. On peut avoir autant de 0 en début de nombre que l'on veut. 0000001 sera reconnu comme 1.

Les nombre décimaux sont les float en Single Precision sur 32 bits, donc entre -3.4e38 .. 3.4e38. La représentation autorisée est proche de celle que l'on a prise pour les entiers, pas de notation scientifique. Un nombre décimal contient donc un entier, suivi obligatoirement d'un seul symbole séparateur entre la partie entière et la partie décimale suivi d'un autre entier qui comportera au moins 1 chiffre valide.
Le séparateur décimal est le point '.'

La fonction retourne true si elle a pu s'exécuter correctement, false si une incompatibilité a été détectée (y compris de représentation de nombre).

Donc par exemple -az---a//+0123.45-----azlkkma678,900blabla doit identifier comme décimal 123.45 et comme entiers 678 et 900

Critères d'évaluation dans l'ordre d'importance:

  • résultat correct
  • respect du cahier des charges
  • vitesse d'exécution de la fonction telle que calculé avec un appel à micros() avant la fonction et en sortie de fonction (avec interdiction de toucher aux interruptions ni au timer contrôlant micros())
  • impact sur l'utilisation de la mémoire (nombre d'octets nécessaires au bon déroulement de la fonction en dehors des paramètres).

Exemples de cas test (n'hésitez pas à en ajouter si nécessaire) :

  • "Day: 14/01/2019, Time 12:25:07" --> renvoie 6 entiers {14,1,2019,12,25,7}
  • "Temperature 12.3 C - Humidite 75%" --> renvoie un float 12.3 et un entier 75
  • "((123-45)/67.89)-(98*76.5)/(43.21+0123)=?" --> renvoie 3 float {67.89,76.5,43.21} et 4 entiers {123,-45,98,123}
  • "((123 - 45) / 67.89) - (98 * 76.5)/(43.21 + 0123)=?" --> renvoie 3 float {67.89,76.5,43.21} et 4 entiers {123,45,98,123}
  • "abc123def---456gh1.2345!*_()-9.8765yz" --> renvoie 2 float {1.2345,-9.8765} et 2 entiers {123,-456}

Qu'en pensez-vous ? S'il n'y a pas suffisamment de personnes intéressées, pas la peine d'aller plus loin à mon avis...

Moi ça me plait mais je vais viser les places du fond du classement :smiley: !

Il y aurait un "sujet" défini au départ : un truc relativement "simple" et accessible au plus grand nombre.

Pour moi ça évoque un "Figure of eight challenge(1)" avec un buggy à 7€, pas un cahier des charges long comme "Guerre et Paix".

Tel quel votre truc n'est pas fun.

(1) Faire un parcours en forme de 8. Engins aquatiques et aeronefs bienvenus.

Notre cahier des charges n'est guère épais, pourtant...

Je comprends ce que tu veux dire. Mais il faut bien expliquer le contenu du challenge et faire en sorte que tous le comprennent de la même façon. Et il faut aussi trouver un sujet qui permette de se creuser un peu les méninges : si c'est pour faire clignoter une led, je ne vois pas l'intérêt.

Tout est ouvert, on peut penser à d'autre sujets, pour l'instant ce n'est qu'une phase de préparation.

Sinon pour faire du fun on peut proproser de faire un jeu avec les leds de bricofoy

Il faudrait que Bricofoy documente son montage hardware (qui doit être assez simple à faire sur breadboard)

La mesure de succès = vote des participants (application qui ne plante pas, facile à lire, sans bugs visible par les membres du forum, et s’installe sur la spec hardware, et jeu addictif)

Le prix => Bricofoy envoie une copie de la boîte gravée et prête à monter (merci bricofoy :slight_smile: ), en échange il peut utiliser tous les jeux (On peut prévoir une cagnotte pour financer le Matos et expédition au gagnant :slight_smile: )

@lesept

Ca me foutrait les boules de savoir que tout ceux qui ne connaissent pas les pointeurs vont se tirer après avoir lu le premier paragraphe du cahier des charges.

Un concept simple admet le plus grand nombre de participants. Ca n'oblige pas à faire simple, ça le permet.