If anybody is interested, I have written a short note on how to select the parameters of an aligned stereovision system (baseline and focal/field of view).
Nothing too complicated, only some basic geometry and some "gnuplotting".
It is hosted on my labs web site, the link is here.
It will probably be updated in some time, 'cause the plots don't look too nice, specifically when printed on a mochrome printer ;-), I'll let you know
Mostly computer stuff.
Please check my other pages for more information, this one is for quick and easy web publishing.
jeudi 8 juillet 2010
jeudi 3 juin 2010
Des pièges de l'utilisation des références C++
Le langage C++ a introduit la notion de "référence", en sus des pointeurs du langage C. Les références permettent notamment la mise en oeuvre du polymorphisme, élément fondamental de la POO. De ce fait, on a parfois tendance à les considérer comme des "pointeurs-bis", permettant juste une syntaxe plus légère tout en ne "trimballant" que l'adresse de l'objet. Par exemple, lors d'un passage d'argument à une fonction:
La référence EST l'objet
Ce point clé trouve son illustration dans un cas fréquent, à savoir la permutation de deux objets selon une condition. La méthode naïve consiste à faire une permutation circulaire:
Mais cette solution est évidemment peu adaptée en pratique: si les objets sont volumineux (comprendre:plusieurs ko ou plus), les performances sont médiocres: 3 copies de l'objet sont nécessaires.
La STL fournit aussi une solution: l'algorithme std::swap(). Mais en pratique, il fait la même chose.
On est alors tenté de travailler sur l'adresse de l'objet, et on pense alors naturellement aux pointeurs:
Ceci fonctionne très bien.
Le piège consiste alors à se dire "les pointeurs, c'est mal, remplaçons tout ça par des références, c'est bien plus dans l'esprit du C++". Soit:
En conclusion, se souvenir que bien que leur utilisation soit bien moins fréquente que en C, l'utilisation des pointeurs reste parfois utile en C++.
A voir aussi:
* La FAQ Developpez
* LaFAQ de Marshall Cline, au paragraphe 8.5:
How can you reseat a reference to make it refer to a different object?
No way. You can't separate the reference from the referent.
Edit 201204: Comme noté ci-dessus, l'algo std::swap() réalisait des copies des objets, ce qui est inacceptable dans certains cas. La nouvelle norme du C++ (C++11) fournit l'algo std::move() qui s'appuie sur le fait que la "r-value" (objet temporaire situé à droite de l'opérateur d'affectation) n'est jamais réutilisé, et qu'on peut donc directement copier l'adresse. On peut donc désormais "encore plus" éviter les pointeurs bruts. Voir les détails ici.
void MaFonction( const MaClasse& objet )
{
objet.FaireCeci();
}
Il y a cependant une petite subtilité, qui peut entraîner des erreurs. Cette particularité peu évidente pour le programmeur novice peut être résumée par la phrase:Ce point clé trouve son illustration dans un cas fréquent, à savoir la permutation de deux objets selon une condition. La méthode naïve consiste à faire une permutation circulaire:
MaClasse objet1;
MaClasse objet2;
...
if( condition )
{
MaClasse objetTemp( objet1 );
objet1 = objet2;
objet2 = objetTemp;
}
Mais cette solution est évidemment peu adaptée en pratique: si les objets sont volumineux (comprendre:plusieurs ko ou plus), les performances sont médiocres: 3 copies de l'objet sont nécessaires.
La STL fournit aussi une solution: l'algorithme std::swap(). Mais en pratique, il fait la même chose.
On est alors tenté de travailler sur l'adresse de l'objet, et on pense alors naturellement aux pointeurs:
MaClasse objet1;
MaClasse objet2;
MaClasse* p1 = &objet1;
MaClasse* p2 = &objet2;
if( condition )
{
p2 = &objet1;
p1 = &objet2;
}
// attention, dans la suite on doit travailler avec l'opérateur '->'
p1->FaireCeci();
p2->FaireCela();
Ceci fonctionne très bien.
Le piège consiste alors à se dire "les pointeurs, c'est mal, remplaçons tout ça par des références, c'est bien plus dans l'esprit du C++". Soit:
MaClasse objet1;
MaClasse objet2;
MaClasse& r1 = objet1;
MaClasse& r2 = objet2;
if( condition )
{
r2 = objet1;
r1 = objet2;
}
// Ouf! Maintenant, je peux me passer de '->' et travailler avec '.'
r1.FaireCeci();
r2.FaireCela();
Et non! Le code ci-dessus est faux. En effet, comme indiqué précédemment, la référence EST l'objet. Donc si 'condition' est vrai, la première affectation (r2 = objet1;) écrase objet2, vu que r2 a été initialisé sur objet2: r2 et objet2 désignent le même espace mémoire. Son contenu est donc perdu, et on se retrouve avec deux objets identiques.En conclusion, se souvenir que bien que leur utilisation soit bien moins fréquente que en C, l'utilisation des pointeurs reste parfois utile en C++.
A voir aussi:
* La FAQ Developpez
* LaFAQ de Marshall Cline, au paragraphe 8.5:
How can you reseat a reference to make it refer to a different object?
No way. You can't separate the reference from the referent.
Edit 201204: Comme noté ci-dessus, l'algo std::swap() réalisait des copies des objets, ce qui est inacceptable dans certains cas. La nouvelle norme du C++ (C++11) fournit l'algo std::move() qui s'appuie sur le fait que la "r-value" (objet temporaire situé à droite de l'opérateur d'affectation) n'est jamais réutilisé, et qu'on peut donc directement copier l'adresse. On peut donc désormais "encore plus" éviter les pointeurs bruts. Voir les détails ici.
mercredi 21 avril 2010
C++ & STL : les pièges du conteneur 'vector'
Le conteneur 'vector' est très pratique d'utilisation mais souffre à mon avis d'un défaut majeur: il est trop tolérant avec l'utilisateur, ce qui se retourne après (souvent...) contre celui-ci.
Par exemple, l'opérateur [] est défini, ce qui rend l'usage de ce conteneur intuitif pour les programmeurs venant du C, en remplacement des tableaux. On pourra ainsi écrire:
de la même façon qu'on écrivait en C:
Mais ceci se révèle après coup TRES DANGEREUX. En effet il n'y a pas de vérification de la validité de l'indice dans cette notation. En vérifiant dans l'implémentation de Mingw, on y trouve le commentaire suivant:
Ceci est d'ailleurs rappelé sur la page Wikipedia du conteneur 'vector'.
Et que ce passe-t-il en pratique ? Et bien, loi de Murphy oblige, ça arrive un jour ou l'autre (croyez moi...). Et donc, crash. Bon, un crash, soit, mais... et alors me direz vous ?
Et bien, ce type de crash est lié à une corruption mémoire, et le problème, c'est qu'il est extrêmement difficile à pister. Contre toute attente, le crash ne se produit pas lors de l'exécution de l'accès au vector, mais à un autre endroit du programme, là où rien de spécial n'est exécuté...
En conclusion, si vous avez moins de 5 ans d'expérience en C++, et que vous travaillez sur un projet conséquent en C++, ne jamais utiliser la notation '[]' mais TOUJOURS la méthode 'at()', qui effectue la vérification de validité d'indice.
* Liens:
Par exemple, l'opérateur [] est défini, ce qui rend l'usage de ce conteneur intuitif pour les programmeurs venant du C, en remplacement des tableaux. On pourra ainsi écrire:
vector<int> tab(10); tab[0] = 3;
de la même façon qu'on écrivait en C:
int tab[10]; tab[0] = 3;
Mais ceci se révèle après coup TRES DANGEREUX. En effet il n'y a pas de vérification de la validité de l'indice dans cette notation. En vérifiant dans l'implémentation de Mingw, on y trouve le commentaire suivant:
This operator allows for easy, array-style, data access. Note that data access with this operator is unchecked and out_of_range lookups are not defined.
Ceci est d'ailleurs rappelé sur la page Wikipedia du conteneur 'vector'.
Et que ce passe-t-il en pratique ? Et bien, loi de Murphy oblige, ça arrive un jour ou l'autre (croyez moi...). Et donc, crash. Bon, un crash, soit, mais... et alors me direz vous ?
Et bien, ce type de crash est lié à une corruption mémoire, et le problème, c'est qu'il est extrêmement difficile à pister. Contre toute attente, le crash ne se produit pas lors de l'exécution de l'accès au vector, mais à un autre endroit du programme, là où rien de spécial n'est exécuté...
En conclusion, si vous avez moins de 5 ans d'expérience en C++, et que vous travaillez sur un projet conséquent en C++, ne jamais utiliser la notation '[]' mais TOUJOURS la méthode 'at()', qui effectue la vérification de validité d'indice.
* Liens:
- STL : voir wikipedia fr, ou wikipedia en.
- FAQ Developpez STL.
- un excellent cours de Bruno Garcia.
jeudi 11 février 2010
Enhancement to the \todo command with doxygen
I use doxygen for my code development, and use a lot the \todo command: it allows me to quickly mention things that need to be done when I don't have time to do it at the moment. This way things don't get buried into my memory.
The problem is that this produces a list that is not sorted in any way: you can't distinguish between things that are important and things that are just some ideas that need to be tried. Just see an example of what an unordered list looks like, in some random project I came across: www.portaudio.com/docs/v19-doxydocs/todo.html.
If your list has 10 or less items, that's not too bad. However, if you manage a large project, you can easily end up with a list with several dozens of items, and this list then becomes useless: the day you happen to have some spare time, you just can't spot what's really important to do... I thought that there was some kind of feature lacking in doxygen, in order to produce some hierarchical "todo" list using different \todo commands (say, \todo1 for top-priority things to do, \todo2 for less important things, and so on).
So I suggested this feature on the doxygen list, to see if other people find it useful, and if it could be added to the wish-list (again, another "todo" list!)
I discovered that this was already possible, by defining an alias in the doxyfile. Thanks to Clemens Feige, he explained to me how to define new commands that do the job, based on the \xrefitem command.
Using this command is not obvious, so I post here the way to do it.
Using a text editor, open your doxyfile and find the ALIAS line, and add the following lines:

In your code, you can now use either \todo, that will end up in the classical unsorted "todo" page, or \todo1, \todo2, or \todo3. Run your doxyfile, and that's it!
For more about code documentation, you can check the following pages:
The problem is that this produces a list that is not sorted in any way: you can't distinguish between things that are important and things that are just some ideas that need to be tried. Just see an example of what an unordered list looks like, in some random project I came across: www.portaudio.com/docs/v19-doxydocs/todo.html.
If your list has 10 or less items, that's not too bad. However, if you manage a large project, you can easily end up with a list with several dozens of items, and this list then becomes useless: the day you happen to have some spare time, you just can't spot what's really important to do... I thought that there was some kind of feature lacking in doxygen, in order to produce some hierarchical "todo" list using different \todo commands (say, \todo1 for top-priority things to do, \todo2 for less important things, and so on).
So I suggested this feature on the doxygen list, to see if other people find it useful, and if it could be added to the wish-list (again, another "todo" list!)
I discovered that this was already possible, by defining an alias in the doxyfile. Thanks to Clemens Feige, he explained to me how to define new commands that do the job, based on the \xrefitem command.
Using this command is not obvious, so I post here the way to do it.
Using a text editor, open your doxyfile and find the ALIAS line, and add the following lines:
ALIASES += "todo1=\xrefitem todo1 \"High Priority Todo\" \"Todo high priority list\"" ALIASES += "todo2=\xrefitem todo2 \"Medium Priority Todo\" \"Todo medium priority list\"" ALIASES += "todo3=\xrefitem todo3 \"Low Priority Todo\" \"Todo low priority list\""

In your code, you can now use either \todo, that will end up in the classical unsorted "todo" page, or \todo1, \todo2, or \todo3. Run your doxyfile, and that's it!
For more about code documentation, you can check the following pages:
mercredi 23 décembre 2009
Excel 2000/2003 bug

Trouvé ce jour un bug sous la version française de Excel 2003. Rien d'extraordinaire, vous me direz... Je publie néanmoins parce qu'il est a mon sens révélateur de la philosophie des produits Microsoft (à laquelle je suis de plus en plus réfractaire).
Le descriptif du bug:
- dans une cellule, taper les 3 lettres "dec"
- copier/coller (CTRL-C/CTRL-V) cette cellule, et la coller dans celle du dessous.
- Sélectionner les 2 cellules, puis à la souris, pointer la poignée (coin inférieur droit de la sélection), clic-gauche, et on descend (recopie incrémentale).
Comme on a sélectionné deux cellules identiques, il n'y a bien sur pas incrémentation, par contre, Excel transforme le contenu des cellules en "déc".
On pourrait se dire qu'il s'agit du formatage automatique de la cellule en fonction de ce qu'on saisit dedans. Exemple, je tape "1/1/09" dans une cellule, et il considère ça comme une date, et active le formatage adéquat. Du coup, si dans la même cellule, je retape "1", il m'affiche "01/01/1900". Déjà ça, c'est limite, mais on s'y fait (si, si...)
Mais en l'occurrence, non, c'est même pas ça ! Si dans une cellule copiée contenant "déc", je saisis "1", j'obtiens bien "1" affiché !
Voilà bien le genre de chose qui m'horripile au plus haut point. Lui se dit : "bon, ce crétin parle du mois de décembre, mais il ne sait pas qu'il y a un accent, alors je vais lui mettre l'accent, dans son dos, sans rien lui dire"
Je ne supporte pas qu'un programme fasse des trucs dans mon dos. Qu'il me fasse des suggestions, des propositions, tout ce qu'on veut, mais quand je tape 3 lettres, que je copie ensuite, je ne veut pas qu'il me les change. C'est moi qui connait la sémantique derrière mes saisies clavier, je ne lui demande pas de faire des hypothèses là-dessus.
Après essais, existe aussi dans la version 2000. Et sur 2007 ?
mercredi 9 décembre 2009
Transforming column datafiles into line datafiles on Windows

In the field of computer science, you frequently need to visualize data: it always makes things clearer when you show a chart, the reader gets the picture just by looking at it, without having to read the painfull 15-lines paragraph below.
So you have data. Sometimes lots of data. Sometimes badly organised text data files. For instance, where successive values are not on successive lines, but on successive columns. This might not be clear for everybody, so here is an example. Say you have a file containing temperatures measured every hour, for some period of time (a month, for instance). The usual way of doing is one measure per line:
and so on. And sometimes you run across datafiles where the layout is:
1/1/2009;0;22
1/1/2009;1;23
1/1/2009;2;22.5
2/1/2009;0;24
...
While regular people won't find anything bad about this (it does indeed save some disk space!), this type of layout is actually unlogical: columns are supposed to be the different fields of data, not successive values. And it makes things more complicated when it comes to plotting...
1/1/2009;22;23;22.5
2/1/2009;24; ...
...
I ran across this issue when trying to illustrate my previous post on gnuplot with a nice figure. I wanted to have a fancy "real-world data" illustration, so I downloaded electricity daily consumption datafiles from RTE (you can get those here). They provide Excel files per year, with 365 lines, one per day, and the power consumption for every half-hour (48 values per day). And guess what, the layout is just as described here...
So, first, before writing an adequate gnuplot script file, you need to transform columns into lines. And this is what this post is about, for Windows users. It can also be considered as a demo of what you can do with the Windows command-line interpreter.
A quick search shows some interesting material, mostly based on Linux tools (see here for example). And yes, Windows users, you'll need to get some new software, because Windows lacks some basic tools. At present we will only need the 'cut' tool, a binary can be downloaded through the gnuwin32 coreutils package.
What we need to do here is to process each line of the file, cut it into fields, and write a one datum per line output datafile. So, lets go first for the line-by-line processing, using the for command (you have of course already converted the file to .csv format):
Of course, you will have previously put the file name into the 'file' variable with set file=myfile.csv. The "delims" item is there just to get the whole line of data.
for /F "delims=." %%a in (%file%) do call :sp1 "%%a"
Then, we need to produce one output file for every column that contains a data value. This is done with the "numeric" version of the 'for' command:
Finally, cut the same line 48 times, and add each of the columns to the output files (column 1 is the date, column 2 is some non-significant data, the first value is in column 3):
--------------------------------------------
:sp1
set line=%~1
echo %line% >line.txt
for /L %%b in (1,1,48) do call :sp2 %%b
goto :eof
--------------------------------------------
with the variable 'app' containing "c:\program files\gnuwin32\bin\cut.exe"
--------------------------------------------
:sp2
set /A col=2+%1
"%app%" -d; -f1,%col% line.txt >> all.dat
goto :eof
--------------------------------------------
And that's about it, the output file all.dat will now contain one line per data point. The only thing left is to leave a line between each day, so gnuplot can figure out where the day stops, so sp1 is actually more like:
Finally, we can plot the thing with some classical gnuplot scripting:
...
for /L %%b in (1,1,48) do call :sp2 %%b
:: gnuplot needs 1 blank lines to separate records
echo. >> all.dat
goto :eof
--------------------------------------------
Feel free to comment (english or french) if you'd like more details.
------------------------------------------------------
set title "France power consumption on mondays, 2008\n(data source : RTE)"
set xrange [0:47]
set xlabel "day period"
set ylabel "week"
set yrange [0:51]
set zlabel "MW" offset 0,3
set ztics 30000,10000
set datafile separator ";"
set style data lines
set grid
set pm3d
set surface
set hidden3d
fn="all.dat"
set view 42.0,56.0
unset colorbox
splot fn using 2 every 1:7 notitle
pause -1
set terminal png size 640,480
set output "RTE_2008_monday.png"
replot
------------------------------------------------------
mercredi 25 novembre 2009
A warning on behavior of gnuplot with numerical values

My favorite plotting software is gnuplot. Not that I am an expert in plotting software, it was just the first I really invested time into, after getting tired of ugly Excel plots... But I got used to it, and I like the idea of script-based plotting.
However, I must say it can be quite tricky, and I often stumble upon some things difficult to achieve, or to make them work. Yesterday, after stumbling for several hours (!) through a function plot that did not work as expected, I finally found out why, and discovered a strange "feature" of gnuplot(4.3): it does not treat integer values as floating-point values !
While this seems quite obvious in a programming language (C), I don't understand why it is so in gnuplot. As far as I can see, a plotting app should treat all numbers as "real" numbers (understand "floating-point"). But this seems to be an opinion I don't have in common with the designers of gnuplot.
To make it clear, what I mean is that the value 10*k/3 is NOT the same as k/3*10, if you happen to give k=2
(just plot these two expressions, you'll see what I mean)
To have it correct, you have to type k=2.0
If not, then 10*k/3 will be equal to 6, and k/3*10 will be equal to 0, while you expected to be 6.66. Yep, you got it, integer division striked again...
Maybe this feature is useful in some situations, I have no clue. After searching the manual, this is indeed explained in section 13 ("Expressions"), page 15 for 4.2 version manual. Of course, I discovered this after trying several hours to make the damn thing work...
It must be pointed out that in this case, I knew what the plot was supposed to look like. So I was able to track down where the problem was. In most situations, such an error is most likely to stay undetected most of the time, until one day, with one particular case of data, you get a plot full of nonsense...
Inscription à :
Articles (Atom)