OVH Cloud OVH Cloud

[Calcul] Problème étrange

69 réponses
Avatar
Rincevent
Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel résultat)

2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction floor()
à (a/b)*c (motif : l'argument n'est pas un double...)


- Je suppose qu'il doit exister une fonction pour convertir des rapports
d'entier en double, non ?
- Et inversement pour passer d'un double codant un entier --> en type int ?
- floor() attend un double comme argument... Soit mais quel est le type duy
résultat ? un double ? un int ?
- comment résoudre cet épineux problème de façon élégante ??? ;-)

Quelqu'un peut-t-il m'aider ?
Merci d'avance !

Rincevent

10 réponses

3 4 5 6 7
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
writes:

[...]
| Sérieusement, au moins dans la partie STL (et c'est bien là où on
| trouve l'introduction des size_t au bout de bras), c'est bien la
| troisième motivation ci-dessus qui a joué, au moins en partie.
| N'oublie pas que Stepanov a beaucoup développé sur un PC, à un
| époque où les PC étaient des machines à 16 bits (mais que les
| pointeurs avec 32 bits). Vouloir un vector<char> avec 40000
| caractères (quand on peut avoir jusqu'à 640 Ko de mémoire totale)
| n'est pas si étrange que ça.

Je ne sais plus si c'est Stepanov qui a introduit ces size_type
non-signés. J'avais demandé à un grand expert qui a une horreur
incroyable de size_t comme type d'indice de tableau (dans la
bibliothèque), il m'a grosso modo répondu que c'était probablement
apparu un jour où il ne surveillait pas ce qui se passait dans le
LWG...

Bon, il était midi, on allait déjeuner et les discussions de café
n'ont pas forcément le poids d'une réponse traditionelle, alors si
jamais quelqu'un me cite, faites attention que c'était une discussion
de café :-)


Mon information est à peu près pareil ; une remarque qu'on m'a fait en
passant, lors d'une discussion d'autre chose. En plus, je ne me rappelle
même plus qui me l'a fait (mais c'est sûrement quelqu'un de moins expert
que ton expert:-)).

N'empêche que la raison tient la route. Pour quelqu'un qui développe
dans ce contexte particulier -- je ne crois pas que la norme aurait dû
faire des compromis pour des implémentations et des utilisations
particulières.

Il y a un contexte historique à prendre en considération, bien que je
crois qu'au moment où on arrivait à voter la STL, il appartenait déjà au
passé. Lors de la normalisation de C, il y a eu beaucoup de discussions
la-dessus. À l'époque, les restrictions des machines 16 bits étaient
très actuelles, et les implémenteurs qui ciblait les processeurs Intel
voulait bien ce bit supplémentaires. C'est par exemple, pourquoi memcpy
et al. prend la longueur sur un size_t.

Dans le contexte de et à l'époque de la norme C, je crois que cette
décision pourrait se justifier, même si je n'étais déjà pas d'accord. À
l'époque où Stepanov expérimentait avec la STL, probablement aussi, bien
qu'elle se justifie moins pour des classes avec une structure et un type
que pour quelque chose d'aussi fondamental que memcpy. À l'époque où on
votait la STL, en revanche, je ne crois pas.

[...]

| > Ceci dit, je crois que c'est un « erreur » qui est du même niveau
| > que les conversions implicites à perte de valeur :

| Pas du tout. Les conversions implicites à perte de valeur est une
| erreur de conception pûre et simple. Stroustrup n'avait pas le
| choix, à cause de la compatibilité C. En fait, je crois que l'«
| erreur » vient du fait que C dérivait au départ de B, qui lui
| n'avait pas de types du tout (et donc, pas de conversions). Mais le
| fait qu'il y a une excuse ne veut pas dire que ce n'est pas une
| erreur.

yep. Et en lisant le D&E et en faisant attention au champ lexical
qu'il utilise dans le chapitre « Overloading » (et si on connait en
général son ton réservé), on s'aperçoit qu'il n'apprécie vraiment pas
ces conversions chaotiques.


Je ne me souviens plus très bien, mais il me semble que ton expert a eu
deux propositions (assez tardives) au comité qui ont été réfusées par le
comité. Un, c'était de rendre les actions qui pourrait confondre une
ramasse-miettes comportement indéfini. Et l'autre, c'était de deprécier
les conversions implicites à perte.

Comme j'ai dit, je ne suis plus vraiment sûr. Ce sont des souvenirs
vagues, d'un époque où je ne consacrais pas beaucoup de temps à la
normalisation. Je n'ai donc pas voulu le dire. Mais puisque tu es dans
une position où tu pourrais éventuellement les confirmer ou les nier...

En ce qui me concerne, j'en aurais été pour tous les deux.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
kanze
Pierre Maurette wrote in message
news:...
typa:
[...]
Malheureusement, C/C++ n'a pas des types à sous-étendu (subrange
types). On peut les implémenter au moyens des classes, mais le
résultat est assez lourd. Alors, en général, on s'en passe.
(Peut-être à tort, je ne sais pas. Un template Subrange< typename T,
T, T > ne doit pas poser de grands problèmes.)


Peut-être y a-t-il un problème de livre et/ou d'enseignement à vouloir
présenter immédiatement les applications lourdes des classes, à partir
d'exemples (les chats, les avions) dont la traduction informatique est
peu convaincante. Bon, d'autres exemples sont quand même mieux
choisis, et certains livres n'ont pas ce défaut.


Je ne suis pas sûr de comprendre ce que tu essaies de dire ici (ou quel
rapport il a avec ce que j'ai dit).

J'aime bien la première phrase sur les classes dans un référence IBM :
"A class is a mechanism for creating user-defined data types."


Tout à fait. On ne pourrait guère trouver une meilleur définition.

Question:
Le fait qu'il y ait en C++ des types qui ne sont pas des classes
(contrairement à Java par exemple) permet-il des choses impossibles
dans le cas contraire ?


Encore, je ne saisis pas ce que tu essaies de démander. Et en C++ et en
Java, il y a des types primitifs, et des classes. (En C++, il y a aussi
plus, évidemment : des pointeurs, des tableaux qui ne sont pas des
classes, des enums...)

Il y a bien en C++ des opérateurs que tu ne peux pas surcharger. Si la
présence d'un tel opérateur est importante pour ce que tu veux faire, tu
es coincé. (On ne peut pas, par exemple, définir des références
intelligentes, comme on définit des pointeurs intelligents, parce qu'on
ne peut pas surcharger l'opérateur . comme on surcharge l'opérateur ->.)

En fait, les seuls opérateurs qu'on ne peut pas surcharger, c'est bien
., .* et ?:, ainsi que les opérateurs qui se résolvent complètement à la
compilation, comme sizeof, ::, # et ##.

Si le but est d'imiter d'aussi près que possible un type fondamental, on
est aussi limiter du fait que toutes les conversions qu'on peut définir
compte comme des conversions définies par l'utilisateur. On perd donc un
peu dans la subtilité de la résolution du surcharge, et on se trouve
plus facilement avec des ambiguïtés.

(Je ne suis pas sûr que ce dernier paragraphe est clair. Un petit
exemple, peut-être, montrait ce que je veux dire :

struct S ;
struct T { T( S ) ; } ;
struct S { S( int ) ; } ;

template< typename U >
void
f( U arg )
{
T var( arg ) ;
}

Je peux instantier f pour tout type arithmétique défini dans la norme,
mais il n'existe pas la possibilité de définir une classe, disons
CheckedInt, pour laquelle une instantiation serait légale.)

Je suppose que si la réponse est "oui", c'est vers les applications
bas niveau que ça se situera.


Je ne sais pas où tu veux en venir. C'est sûr que le fait d'avoir des
pointeurs (en tant qu'objet en soi) permet énormement de choses qu'on ne
peut pas faire en Java. Si on se situe au bas niveau (écriture d'un
système d'exploitation, d'une ramasse-miettes, etc.), non seulement les
pointeurs, mais la possibilité de régarder l'objet comme un tableau de
bytes devient important aussi.

Mais je ne pense pas, c'est plus la notion de pointeur et l'opérateur
adresse & qui rend le langage si universel.


Tu ne penses pas quoi ? Le fait qu'un pointeur est un objet permet
certaines choses qui ne seraient pas possible autrement. L'arithmétique
sur des pointeurs aussi. Et le fait qu'un pointeur peut pointer
n'importe où, par exemple, à une variable locale. En général, ces choses
sont surtout intéressantes à bas niveau, mais pas exclusivement ; c'est
même souvent assez utile de prendre l'adresse d'une variable locale ou
statique.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
kanze
Loïc Joly wrote in message
news:<c92js0$n2g$...
wrote:
Pour les classes on conseille de s'inspirer de "l'univers du
problème" ; serait-ce une tare de faire de même pour d'autres types,
encore plus basiques ? Quand une variable représente un entier qui
n'a aucun sens autre que positif, cela me révulse absolument qu'il
ne soit pas unsigned.


Tu veux dire que ça te révulse qu'il puisse représenter les valeurs
en dehors du domaine. Moi aussi. Par exemple, si je veux un type qui
représente un dé, je ne veux pas non plus qu'il puisse représenter
un 0, ou un 100.


Si tu faisais des jeux de rôle, un dé valant 0 ou 100 ne te ferait pas
peur... ;)

Malheureusement, C/C++ n'a pas des types à sous-étendu (subrange
types). On peut les implémenter au moyens des classes, mais le
résultat est assez lourd. Alors, en général, on s'en passe.
(Peut-être à tort, je ne sais pas. Un template Subrange< typename T,
T, T > ne doit pas poser de grands problèmes.)


Je pense que ce n'est pas trivial quand même. En particulier :
Subrange<int, 0, 10> a, b;

Quel doit être le type de a-b ? Subrange<int, 0, 10>, ou bien
Subrange<int, -10, 10> ?


Pascal a choisi le premier. C'est, je crois, une solution de facilité.

Dans la pratique, je crois que la question est peut-être mal posée. La
plupart du temps, je crois, on aurait subrange + int -> subrange, ou
subrange - int -> subrange. Voire rien de tout, ou quelque chose
spécifique à l'application. Ajouter deux dés, ça a un sens, mais le
résultat n'est pas un dé. On pourrait même argüer qu'ajouter deux dés
n'a pas de sens, ce qu'il faut ajouter, c'est la valeur de chaque dé.

Et à ce moment, on revient bien à l'aspect objet de C++ : Dé devient une
classe, avec, entre d'autres, une attribute « valeur » qu'on pourrait
intérogée. Et c'est l'attribute qui ne pourrait prendre que les valeurs
d'un à six, mais c'est assez simple à enforcer cette invariante de
classe dans la classe.

(Ce qui nous amène à la discussion du départ. Moi, je déclarerais la
variable membre qui contient cette attribute avec un type int. Pourquoi
int, et non unsigned ? Parce que int est le type naturel des entiers en
C++, et l'utilisation que j'en fais n'a pas besoin des fonctionalités
particulières de unsigned.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
"Alain Naigeon" wrote in message
news:<40b4a8ed$0$12744$...
a écrit dans le message news:


Tu veux dire que ça te révulse qu'il puisse représenter les valeurs
en dehors du domaine. Moi aussi. Par exemple, si je veux un type qui
représente un dé, je ne veux pas non plus qu'il puisse représenter
un 0, ou un 100.

Malheureusement, C/C++ n'a pas des types à sous-étendu (subrange
types).


Certes je regrette beaucoup le type intervalle du Pascal. Ceci dit, je
ne suis réaliste, travaillons avec ce qu'offre le langage.


Tout à fait. Le langage n'offre pas de type Cardinal (à l'encontre de
Modula 2, par exmple). Il a des types dont l'arithmétique obéit aux
règles de l'arithmétique des entiers, dans la mésure où il n'y a pas de
débordement (et le débordement, dans ce cas-là, est un comportement
indéfini -- une implémentation peut le detecter, et en faire quelque
chose de raisonable, comme aborter le processus). Ces types existent en
plusieurs tailles, mais dans la pratique, la plupart se convertit en int
dès qu'ils apparaissent dans une expression.

Il y a aussi des types sur lesquels on a défini un arithmétique modulo
un peu particulier. Un arithmétique qui n'est pas l'arithmétique des
entiers.

Alors, si je veux un entier, je choisis un type où l'arithmétique est
défini être celle des entiers.

Ce que je dis simplement, c'est que s'il existe un type, alors c'est
vraiment bizare de s'en passer.


Ça dépend. Il existe un type double. Je m'en passe dans mes
applications, et je ne trouve pas ça bizarre ; il s'avère que mes
applications n'utilisent pas l'abstraction que double implémente. En
revanche, je me sers bien de unsigned -- pour calculer un hachage, par
exemple, où la sémantique en convient parfaitement (et c'est une chose
que je fais réelement dans mes applications).

A moins que le langage ne nous trompe ;


Il nous trompe un peu, oui, par les noms. Par exemple, double est le
type « naturel » pour des calculs en virgule flottant, or que d'après le
nom, on s'attendrait à ce que ce soit float. Il appelle push(_back) une
opération qui partout ailleurs s'appelle append, et qui n'a rien à voir
avec ce que je m'attends d'un « push ». Et il appelle unsigned un type
qui fait de l'arithmétique modulo.

Ce qui importe, ce n'est pas le nom, mais ce qui est derrière.

si les "unsigned int" et leurs opérations autorisées (par le langage
!) ne se comportent pas comme des entiers sans signe, alors ce n'est
plus de café qu'il faut parler, mais de pousse-café :-)


C'est malheureusement le cas.

Etre averti des problèmes d'implémentation numérique (et toi tu l'es
!), c'est bien. Mais prenons garde à ne pas penser les nombres à
partir de leur implémentation.


Justement. Dans la pratique, dans la plupart des implémentations, un int
manifeste un arithmétique modulo aussi. Mais dans le cas de int, c'est
un artifact de son implémentation (et ce n'est pas nécessairement vrai
partout). On n'en tient pas compte. Chez les unsigned, en revanche,
l'arithmétique modulo est en fait leur caractèristique définissant ; on
ne s'en sert que c'est c'est l'arithmétique modulo qu'on veut.

Un entier sans signe, cela a un sens.


En mathématique, je ne crois pas qu'on parlera des entiers sans signes.
On dirait plutôt un nombre naturel, ou un cardinal. Cela a un sens. Mais
il n'y a pas de type de base en C++ qui correspond.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Gabriel Dos Reis
writes:

[...]

| > | > Ceci dit, je crois que c'est un « erreur » qui est du même niveau
| > | > que les conversions implicites à perte de valeur :
|
| > | Pas du tout. Les conversions implicites à perte de valeur est une
| > | erreur de conception pûre et simple. Stroustrup n'avait pas le
| > | choix, à cause de la compatibilité C. En fait, je crois que l'«
| > | erreur » vient du fait que C dérivait au départ de B, qui lui
| > | n'avait pas de types du tout (et donc, pas de conversions). Mais le
| > | fait qu'il y a une excuse ne veut pas dire que ce n'est pas une
| > | erreur.
|
| > yep. Et en lisant le D&E et en faisant attention au champ lexical
| > qu'il utilise dans le chapitre « Overloading » (et si on connait en
| > général son ton réservé), on s'aperçoit qu'il n'apprécie vraiment pas
| > ces conversions chaotiques.
|
| Je ne me souviens plus très bien, mais il me semble que ton expert a eu
| deux propositions (assez tardives) au comité qui ont été réfusées par le
| comité. Un, c'était de rendre les actions qui pourrait confondre une
| ramasse-miettes comportement indéfini.

Celle-ci est encore d'actualité : il voudrait rendre le ramasse-miette
optionnel en C++.

| Et l'autre, c'était de deprécier
| les conversions implicites à perte.

Je crois qu'il s'est vait une raison pour celle-là :-(

-- Gaby
Avatar
Michel Michaud
Dans news:c9470d$ohu$, Vincent
Je crois que je n'ai pas dit les choses correctement. En disant
« quand il en a besoin » je voulais dire « quand c'est tout
ce dont il a besoin ». Si tu as absolument besoin de la
division entière, je suis sûr que tu la mettras puisque sinon
ton programme ne fonctionnera pas. Mais si la division entière
est suffisante (est tout ce dont tu as besoin), alors que /
(division réelle) fonctionne aussi, tu vas vraiment penser à
mettre ?


Comme ça, là, je ne vois pas de cas (hors les cas triviaux ou
on fait la division de deux entiers dont le dividende est un
multiple du diviseur) ou la division entière et la division
réelle ont des résultats équivalents.


Non, mais quand tu remets la valeur dans un entier oui !

Mais si je tombe sur un tel cas, je pense qu'en effet risque
d'utiliser la division réelle et non pas la division entière.


Par exemple, avec trois entiers, on veut savoir combien de
lignes seront nécessaires pour afficher des noms de clients
en plusieurs colonnes :

nbLignes= (nbClients-1)/nbColonnes + 1

Tout fonctionne, mais en VB, on a conversion des deux nombres
impliqués en réel, division réelle, addition réelle, puis
reconversion en entier pour l'affectation. Au moins trois
opérations inutiles et deux opérations plus lentes que sur des
entiers.

N.B. Peut-être que le compilateur VB fait de l'optimisation et
fera tout le calcul en entier (bien que ça me semble peu
probable qu'il puisse faire l'analyse nécessaire), mais
la discussion n'est pas sur VB mais sur le principe de
la division réelle, même entre entiers.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


Avatar
kanze
"Michel Michaud" wrote in message
news:<fA1tc.41923$...
a écrit dans le message de
news:
"Michel Michaud" wrote in message
news:<EJJsc.27786$...
C'est à peu près ce que je pense aussi, mais les nombreuses
discussions (sur clc++m par exemple) montrent bien que ce n'est
pas complètement noir ou blanc. En particulier, le fait que la
bibliothèque standard regorge de unsigned (pour aucune des raisons
citées plus haut) indique qu'au moins quelques grands experts ont,
pendant un certain temps, pensé autrement.


Ou que la bibliothèque n'est pas le produit des grands experts:-).

Sérieusement, au moins dans la partie STL (et c'est bien là où on
trouve l'introduction des size_t au bout de bras), c'est bien la
troisième motivation ci-dessus qui a joué, au moins en partie.


[... i.e. un bit de plus ...]

N'oublie pas que Stepanov a beaucoup développé sur un PC, à un
époque où les PC étaient des machines à 16 bits (mais que les
pointeurs avec 32 bits). Vouloir un vector<char> avec 40000
caractères (quand on peut avoir jusqu'à 640 Ko de mémoire totale)
n'est pas si étrange que ça.


Hum. Et pourquoi pas simplement prendre un long (minimum 32 bits tout
le temps) pour pouvoir avoir un vecteur de 80 000 éléments ou plus...


Parce que le hardware ne le supporte pas. C/C++ exige que l'adressage à
l'intérieur d'un élément soit linéaire, et la taille maximum qu'on peut
adresser de façon linéairement, c'est bien 64Ko. (Même les solutions en
récalculant le ségment ne marche pas en 80286.)

Avec 640K, on peut aller bien plus aussi. Je ne vois pas pourquoi 40
000 semblerait plus utile que 80 000...


Parce que 40 000, c'est possible, tandis que 80 000 ne l'est pas. Sur le
hardware en question.

Il est clair que l'histoire d'un bit de plus ne peut jouer que sur des
architectures ségmentées, où la mémoire n'est pas adressée linéairement,
et que la taille maximum d'un objet est nettement inférieur à la taille
totale de la mémoire.

Par ailleurs, si je me rappelle bien, à cause des types pour les
distances entre les éléments (ou quelque chose du genre), on ne peut
pas avoir plus du nombre d'éléments du type signé (mais je peux me
tromper...).


Je crois que tu te trompes. Seulement, si tu en as autant, le résultat
de la soustraction des pointeurs devient un comportement indéfini.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Alain Naigeon
"Gabriel Dos Reis" a écrit dans le message
news:
"Alain Naigeon" writes:

| je ne suis réaliste, travaillons avec ce qu'offre le langage. Ce que je
dis

| simplement, c'est que s'il existe un type, alors c'est vraiment bizare
| de s'en passer.

Ce serait vraiment bizarre de se servir d'un type juste parce qu'il
existe non parce que sa sémantique convient.


Je trouve que tu restes elliptique, et un peu coupeur de
cheveux en quatre quand tu évoques la syntaxe à tout
propos.
D'abord le langage commun fait partie de ce qui permet
de communiquer ; même la norme est écrite en langage
humain ;-) Donc, est-ce trop demander qu'un type
appelé "entier" ait la sémantique des entiers ? Parce que
si la réponse est non, alors j'en connais au moins un qui,
en d'autres circonstances, aurait appelé ça de l'obfuscation.
Il me paraît tout de même important de marquer nettement,
pour ceux qui le savent moins que toi, que les entiers
pré-existent à l'informatique, et que si celle-ci propose un
type qui en diffère subtilement, il est très maladroit de
lui donner exactement le même nom.

Pour finir, cela me fait une belle jambe de savoir que la
sémantique est diifférente, si je ne sais pas en quoi elle
diffère.

--

Français *==> "Musique renaissance" <==* English
midi - facsimiles - ligatures - mensuration
http://anaigeon.free.fr | http://www.medieval.org/emfaq/anaigeon/
Alain Naigeon - - Strasbourg, France

Avatar
Alain Naigeon
"Michel Michaud" a écrit dans le message news:
3Zltc.48920$
Dans news:c9470d$ohu$, Vincent
Je crois que je n'ai pas dit les choses correctement. En disant
« quand il en a besoin » je voulais dire « quand c'est tout
ce dont il a besoin ». Si tu as absolument besoin de la
division entière, je suis sûr que tu la mettras puisque sinon
ton programme ne fonctionnera pas. Mais si la division entière
est suffisante (est tout ce dont tu as besoin), alors que /
(division réelle) fonctionne aussi, tu vas vraiment penser à
mettre ?


Comme ça, là, je ne vois pas de cas (hors les cas triviaux ou
on fait la division de deux entiers dont le dividende est un
multiple du diviseur) ou la division entière et la division
réelle ont des résultats équivalents.


Non, mais quand tu remets la valeur dans un entier oui !



Si c'est fait exprès par un cast, on en prend la responsabilité.
Sinon, on doit avoir "conversion may loose digits", non ?


--

Français *==> "Musique renaissance" <==* English
midi - facsimiles - ligatures - mensuration
http://anaigeon.free.fr | http://www.medieval.org/emfaq/anaigeon/
Alain Naigeon - - Strasbourg, France



Avatar
Alain Naigeon
"Loïc Joly" a écrit dans le message news:
c92js0$n2g$
wrote:
Pour les classes on conseille de s'inspirer de "l'univers du problème"
; serait-ce une tare de faire de même pour d'autres types, encore plus
basiques ? Quand une variable représente un entier qui n'a aucun sens
autre que positif, cela me révulse absolument qu'il ne soit pas
unsigned.




Pauvre James, c'est moi avais écrit cela. C'est pas grave,
pas pour moi en tout cas ;-)

--

Français *==> "Musique renaissance" <==* English
midi - facsimiles - ligatures - mensuration
http://anaigeon.free.fr | http://www.medieval.org/emfaq/anaigeon/
Alain Naigeon - - Strasbourg, France



3 4 5 6 7