Offline
Edison Member
Karma: 6
Posts: 2414
|
 |
« on: February 29, 2012, 04:19:47 pm » |
bonsoir appel aux petits génies du C  Je suis plus un homme de capteur qu'un homme du C , en discutant du projet de JF (à prendre là pour la compréhension de la problématique ) http://arduino.cc/forum/index.php/topic,89413.msg708521.html#msg708521Je me suis aperçu qu'un tableau de type boolean occupe sous arduino 1 octet alors qu'un bit suffi(rait)t Par envie de m'y coller , j'en suis arrivé à ça (code) Il y a une approche plus "codeur" pour simplifier ?  void setup() { Serial.begin(115200);
}
unsigned long ray=0; unsigned long top=0; byte pass=0; void loop() { for (pass=0;pass <=254; pass ++) { // pour simuler le taux d'acquisition top = random(02); // pour simulation occultation ou pas top = top << pass; // decalage du masque OR ray=ray | top; //OR
} //ecrire ray Serial.println(ray, BIN); // pour voir les 0 et 1 Serial.println(" "); Serial.println(ray); // pas vraiment utile mais bon !
Serial.println("");
ray=0; //raz et on repart pour un tour
}
|
|
|
|
|
Logged
|
|
|
|
|
Made in Belgium
Offline
God Member
Karma: 0
Posts: 756
|
 |
« Reply #1 on: February 29, 2012, 06:41:21 pm » |
Yop Artouste Je me suis aperçu qu'un tableau de type boolean occupe sous arduino 1 octet alors qu'un bit suffi(rait)t
Quelque soit le type de variable elle occupera toujours minimum 1 octet (1 emplacement mémoire). Le type boolean n'est rien d'autre qu'un "unsigned char" normalement (en c++ seulement, le type boolean n'existe pas en c). tu peux faire : boolean b = 5;
En fait un boolean peux posséder deux états: vrai ou faux, mais dire "1=vrai" et "0=faux" n'est pas tout à fais exact, en fait la véritable définition d'un boolean en programmation devrait être : toute valeur différente de 0 (faux) est considéré comme vrai (1, 1.55555, -1, 255, -128, ....). Preuve : if(238) {} if(-66) {} if(1.5555) {} if(0) {} // sera la seule condition à ne jamais s'executer
J'utilise rarement le "type" boolean, si j'ai plusieurs états à stocker j'utilise 1 (ou plusieurs) octet ce qui me permet 8 états minimum (comme tu l'a fais avec l'unsigned long je pense ?). for (pass=0;pass <=254; pass ++) { // pour simuler le taux d'acquisition top = random(02); // pour simulation occultation ou pas top = top << pass; // decalage du masque OR ray=ray | top; //OR
Un truc me chiffonne dans "top = top << pass;", pass s'incrémente jusque 254 or tu fais un décalage d'après "pass" donc jusqu'à (<< 254) sur top de 32bit donc normalement "<< 31" max. Pour "random(02)" ce n'est pas plutôt "random(1)" -> valeur max 1 (donc 0 ou 1) ? Je ne sais pas si il faut obligatoirement 255 valeurs (0->254) mais pour un unsigned long (32bit) ceci devrait être bon. for (byte pass=0;pass <=31; pass ++) { ray+=(random(1)<< pass); //addition binaire directement sur "ray" même d'après la valeur renvoyer par random décaler selon l'incrémentation. }
Vue de ce qu'il ce passe niveau binaire (c'est identique au système décimal). 0000 0001 //1 << 0 +0000 0010 //1 << 1 +0000 0000 //0 << 3 +0001 0000 //1 << 5 --------------- =0001 0011
|
|
|
|
« Last Edit: February 29, 2012, 07:00:16 pm by osaka »
|
Logged
|
|
|
|
|
Offline
Full Member
Karma: 0
Posts: 218
|
 |
« Reply #2 on: March 01, 2012, 02:30:00 am » |
Salut, Peut-être une piste du côté des champs de bits. Extrait de la page bit field sur Wikipedia) : Kernighan and Ritchie's book, The C Programming Language, describes a method for defining and accessing fields directly. Using this method, bitwise operators are not needed as bit members can be accessed the same as members of a structure without the need to create a object-oriented class like the one above. An example using C's struct keyword and C++'s bool data type follows: typedef struct Preferences { bool likesIceCream : 1; bool playsGolf : 1; bool watchesTv : 1; bool readsBooks : 1; } Preferences; Preferences fred; fred.likesIceCream = true; fred.playsGolf = true; fred.watchesTv = true; fred.readsBooks = false;
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 84
|
 |
« Reply #3 on: March 01, 2012, 04:07:09 am » |
+1 C'est une excellente technique pour optimiser l'occupation de la mémoire, d'ailleurs elle est utilisée (entre autres) dans le bootloader Arduino.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 6
Posts: 2414
|
 |
« Reply #4 on: March 01, 2012, 06:03:02 am » |
Un truc me chiffonne dans "top = top << pass;", pass s'incrémente jusque 254 or tu fais un décalage d'après "pass" donc jusqu'à (<< 254) sur top de 32bit donc normalement "<< 31" max. Pour "random(02)" ce n'est pas plutôt "random(1)" -> valeur max 1 (donc 0 ou 1) ? Je ne sais pas si il faut obligatoirement 255 valeurs (0->254) mais pour un unsigned long (32bit) ceci devrait être bon. for (byte pass=0;pass <=31; pass ++) { ray+=(random(1)<< pass); //addition binaire directement sur "ray" même d'après la valeur renvoyer par random décaler selon l'incrémentation. }
Bonjour oui pour le pass<=31 , je me suis rendu compte que j'avais fait une confusion après avoir éteint mon pc et comme ce coucher tard nuit !  mon probleme se reduit à avoir une succession de 256 bit , il me faut donc 8 unsigned long (8X32=256) en fait j'ai reglé le probleme en utilisant 2 boucles imbriquées for 7 to 0 pour ray[] et for 0 to 31 pour pass pour le random selon la doc max est exclu et en test avec un 1 ça retourne que du 0 , on ne peut pas vraiment appeler ça du random random(max) random(min, max) Parameters min - lower bound of the random value, inclusive (optional) max - upper bound of the random value, exclusive Returns
a random number between min and max-1 (long) ok pour l'addition binaire directe +1 C'est une excellente technique pour optimiser l'occupation de la mémoire, d'ailleurs elle est utilisée (entre autres) dans le bootloader Arduino. bonjour benvenuto merci pour le lien , en fait c'est intuitivement ce que j'avais fait je suis parti sur 8 unsigned long (8X32) , mais in fine 32 [] byte (8 bit) permettent sans déchet la même occupation mémoire pour le meme resultat En ce qui concerne ensuite l'optimisation du process (temps d’exécution) et pour résultat identique c'est préférable d'utiliser du byte ou du long ? , intuitivement je dirais byte gagnant ? , mais .... ? void setup() { Serial.begin(115200);
}
unsigned long ray[]={0,0,0,0,0,0,0,0}; unsigned long top=0; byte pass=0; byte ir=0;
void loop() { for (ir=7;ir >0; ir --) { // pour les 8 postes ray[] 7-->0 // 1er bit top sur 1e LSB ray[7] dernier bit top sur le MSB ray[0] for (pass=0;pass <=31; pass ++) { // pour simuler le taux d'acquisition top = random(2); // pour simulation occultation ou pas top = top << pass; // decalage du masque OR
ray[ir]=ray[ir] | top; //OR
} } //ecrire ray for (ir=7;ir >0; ir --) { Serial.println(ray[ir], BIN); // pour voir les 0 et 1 } Serial.println("-------------------------------- ");
for (ir=7;ir >0; ir --) { ray[ir]=0; //raz et on repart pour un tour }
}
|
|
|
|
« Last Edit: March 01, 2012, 08:18:17 am by Artouste »
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 84
|
 |
« Reply #5 on: March 01, 2012, 09:35:37 am » |
Lorsqu'un programme utilise des types qui occupent plusieurs registres - typiquement des long - le compilateur traite et alloue les registres indépendamment les uns des autres ce qui permet de générer un code machine plus efficace. Il y a une option -fno-split-wide-types qui permet de désactiver cette optimisation, mais elle n'est vraiment utile que pour débugger plus facilement l'assembleur généré et elle est inactive par défaut. Donc en théorie les deux solutions devraient être équivalentes. Si tu as l'occasion de faire un comparatif, ça m'intéresse de savoir si c'est le cas en pratique 
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 6
Posts: 2414
|
 |
« Reply #6 on: March 01, 2012, 02:33:37 pm » |
Lorsqu'un programme utilise des types qui occupent plusieurs registres - typiquement des long - le compilateur traite et alloue les registres indépendamment les uns des autres ce qui permet de générer un code machine plus efficace. Il y a une option -fno-split-wide-types qui permet de désactiver cette optimisation, mais elle n'est vraiment utile que pour débugger plus facilement l'assembleur généré et elle est inactive par défaut. Donc en théorie les deux solutions devraient être équivalentes. Si tu as l'occasion de faire un comparatif, ça m'intéresse de savoir si c'est le cas en pratique  merci pour l'option de désactivation , mais je la laisse là où je l'ai trouvée  par curiosite et sauf à avoir commis une bourde sur un uno IDE 022 le 1er code 8 postes d'unsigned long renvoi ~1694 ms d’exécution pour 50 boucles le 2 eme code 32 postes de byte renvoi ~1784 ms j'ai volontairement squizzé les envois serial sauf en fin de boucle pour ne pas pas polluer avec des longueurs d'affichage différentes 1er codevoid setup() { Serial.begin(115200);
}
unsigned long ray[]={0,0,0,0,0,0,0,0}; unsigned long top=0; unsigned long act=0; byte pass=0; byte ir=0; word ts=0; void loop() { act=millis(); for (ts=0;ts<=50;ts ++) {
for (ir=7;ir >0; ir --) { // pour les 8 postes ray[] 7-->0 // 1er bit top sur 1e LSB ray[7] dernier bit top sur le MSB ray[0]
for (pass=0;pass <=31; pass ++) { // pour simuler le taux d'acquisition top = random(2); // pour simulation occultation ou pas top = top << pass; // decalage du masque OR
ray[ir]=ray[ir] | top; //OR
} } for (ir=7;ir >0; ir --) { ray[ir]=0; //raz et on repart pour un tour } } act=millis()-act; Serial.println(act,DEC); // pour voir les 0 et 1 } 2eme code void setup() { Serial.begin(115200);
}
byte ray[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; byte top=0; unsigned long act=0; byte pass=0; byte ir=0; word ts=0;
void loop() { act=millis(); for (ts=0;ts<=50;ts ++) { for (ir=31;ir >0; ir --) { // pour les 32 postes ray[] 31-->0 // 1er bit top sur 1e LSB ray[7] dernier bit top sur le MSB ray[0] for (pass=0;pass <=7; pass ++) { // pour simuler le taux d'acquisition top = random(2); // pour simulation occultation ou pas top = top << pass; // decalage du masque OR
ray[ir]=ray[ir] | top; //OR
} }
for (ir=31;ir >0; ir --) { ray[ir]=0; //raz et on repart pour un tour }
} act=millis()-act; Serial.println(act,DEC); // pour voir les 0 et 1 }
|
|
|
|
|
Logged
|
|
|
|
|
Made in Belgium
Offline
God Member
Karma: 0
Posts: 756
|
 |
« Reply #7 on: March 02, 2012, 07:01:26 am » |
byte ray[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
ray[ir]=ray[ir] | top; //OR Yop Artouste, Juste au cas ou, parmis les nombreux raccourcis de programmeur fainéant: byte ray[32]={0}; // les 32 emplacements réservés seront bien tous initialisé à 0.
ray[ir] |= top; //équivalent à "ray[ir]=ray[ir] | top;"
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 6
Posts: 2414
|
 |
« Reply #8 on: March 02, 2012, 07:18:22 am » |
byte ray[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
ray[ir]=ray[ir] | top; //OR Yop Artouste, Juste au cas ou, parmis les nombreux raccourcis de programmeur fainéant: byte ray[32]={0}; // les 32 emplacements réservés seront bien tous initialisé à 0.
ray[ir] |= top; //équivalent à "ray[ir]=ray[ir] | top;"
bonjour osaka pas d'accord , je prend ça pour du codage fait par un programmeur aguerri, pas feignant, ce que très humblement je revendique ne pas être dans les 2 cas !  mais c'est vrai que la concision est agréable à regarder ! j'ai fais mes premières armes il y a déjà longtemps avec fortran, je ne suis même plus sur de savoir encore coder du simple avec ! Mais comme avec tous les langages , la syntaxe sans reflechir déjà à ce que l'on veut, quel que soit le langage ça ne sert pas à grand chose. intellectuellement, je suis un peu surpris du résultat, intuitivement je donnais byte gagnant ! comme quoi il faut toujours se méfier des a priori . ça s'explique très surement en regardant ce que le compilo génère dans les 2 cas. Mais là je délègue le challenge à ceux qui veulent s'y coller 
|
|
|
|
|
Logged
|
|
|
|
|
Made in Belgium
Offline
God Member
Karma: 0
Posts: 756
|
 |
« Reply #9 on: March 02, 2012, 08:16:18 am » |
pas d'accord , je prend ça pour du codage fait par un programmeur aguerri, pas feignant, ce que très humblement je revendique ne pas être dans les 2 cas !  mais c'est vrai que la concision est agréable à regarder ! Tu n'imagines pas tout ce que le programmeur est près à faire pour s’épargner une ligne de code.  Par contre certain raccourcis ou facilitées ne me plaise guère tel que : bloc sans accolades: if(condition) blabla code;
for(int i = 0; i < blabla; i++) blabla code;
accolade décalées: if(condition){ blabla code; }
Qui nuisent à la bonne lecture et propreté du code pour moi.  Ou également le typage dynamique fort tels qu'on vois dans certain langages comme python, php, ... (la raison de leurs succès ?) Mais comme avec tous les langages , la syntaxe sans reflechir déjà à ce que l'on veut, quel que soit le langage ça ne sert pas à grand chose.
Le premier outil du développeur: papier, crayon, cerveau (je suis mal barré).  intellectuellement, je suis un peu surpris du résultat, intuitivement je donnais byte gagnant ! comme quoi il faut toujours se méfier des a priori .
Je suis étonné également et n’empêche ce sont des choses auquel je n'aurais jamais pensé (ou même cherché) en développant sur pc classique. 
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 6
Posts: 2414
|
 |
« Reply #10 on: March 02, 2012, 08:35:32 am » |
Je suis étonné également et n’empêche ce sont des choses auquel je n'aurais jamais pensé (ou même cherché) en développant sur pc classique.  d'autant que toujours par curiosité je viens de regarder Binary sketch size: 2658 bytes (of a 30720 byte maximum) pour le 8 unsigned long Binary sketch size: 2598 bytes (of a 30720 byte maximum) pour le 32 byte le code le plus "compact" est (serait) le plus "lent" en exécution 
|
|
|
|
|
Logged
|
|
|
|
|
Made in Belgium
Offline
God Member
Karma: 0
Posts: 756
|
 |
« Reply #11 on: March 02, 2012, 08:43:13 am » |
d'autant que toujours par curiosité je viens de regarder Binary sketch size: 2658 bytes (of a 30720 byte maximum) pour le 8 unsigned long Binary sketch size: 2598 bytes (of a 30720 byte maximum) pour le 32 byte le code le plus "compact" est (serait) le plus "lent" en exécution  Alors là je suis encore plus étonné  . Comme quoi il vaut mieux une longue boucle avec de petite données qu'une petite avec de grosses. (le mythe est tombé) 
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 6
Posts: 2414
|
 |
« Reply #12 on: March 02, 2012, 09:17:59 am » |
d'autant que toujours par curiosité je viens de regarder Binary sketch size: 2658 bytes (of a 30720 byte maximum) pour le 8 unsigned long Binary sketch size: 2598 bytes (of a 30720 byte maximum) pour le 32 byte le code le plus "compact" est (serait) le plus "lent" en exécution  Alors là je suis encore plus étonné  . ... tu a testé les 2 bouts de code ? En bon scientifique si des participants du forum veulent bien vérifier et tester les 2 bouts de codes pour levée de doute (ou débusquer incohérence) size time ?
|
|
|
|
|
Logged
|
|
|
|
|
Made in Belgium
Offline
God Member
Karma: 0
Posts: 756
|
 |
« Reply #13 on: March 02, 2012, 09:45:40 am » |
Je ferais quelques testes tantôt (je dois aller faire les courses  ), mais parfois j'ai constaté dans mes codes une augmentation en mémoire programme alors que je pensais faire le contraire ...  Mystère du compilateurs ? Un poste récent montrait une incrémentation de 2 plus lourde que de 3.
|
|
|
|
|
Logged
|
|
|
|
|
Made in Belgium
Offline
God Member
Karma: 0
Posts: 756
|
 |
« Reply #14 on: March 02, 2012, 06:47:12 pm » |
Ai fait le test avec un résultat identique aux tiens. Voilà comment je vois ton développement: byte ray[32]={0}; unsigned long act=0;
void setup() { Serial.begin(115200); }
void loop() { act=millis(); for (byte ts=0;ts<=50;ts++) { for (byte ir=31;ir >0; ir--) { for (byte pass=0;pass <=7; pass ++) { ray[ir] += random(2) << pass; } } } Serial.println(millis()-act,DEC); delay(1000); }
Le raz était obligatoire ?
|
|
|
|
|
Logged
|
|
|
|
|
|