La fonction atan2 en natif dans CaRMetal

S'il ne s'agit pas vraiment d'une erreur, mais plutôt d'une fonctionnalité que vous souhaiteriez voir dans CaRMetal, c'est ici !
Post Reply
stephrey
Posts: 16
Joined: Thu Jan 20, 2011 3:51 pm
Location: Limoges

La fonction atan2 en natif dans CaRMetal

Post by stephrey » Tue Feb 08, 2011 8:28 pm

Bonjour,

Bien que la fonction atan2 (http://fr.wikipedia.org/wiki/Atan2) existe dans l'API java, elle n'est pas intégrée à CaRMetal.
Dans certains cas, le logiciel de calcul formel Maxima (utilisé par CaRCASMetal - http://db-maths.nuxit.net/CaRMetal/foru ... .php?t=411) s'en sert pour exprimer les parties réelles ou imaginaires d'expressions pouvant s'évaluer comme nombres complexes.

On peut bien sûr rajouté une fonction définie par l'utilisateur que l'on nommera atan2 et dont voici l'expression :

Code: Select all

if(x==0,
   if(y<0, pi, 
   if(y>0, 0,
           0/0)),

   if(y<0, sign(x)*(pi-rarctan(abs(x/y))),
   if(y>0, sign(x)*rarctan(abs(x/y)),
           sign(x)*(pi/2) )) )

Remarque : je laisse aux lecteurs le soin de supprimer les espaces et sauts de lignes qui n'ont été introduits ici que pour améliorer la lisibilité.

Je pense qu'il serait toutefois préférable de la rajouter nativement à CaRMetal.
Vous trouverez en pièce jointe le fichier source original Expression.java provenant de CaRMetal 3.5.2 ainsi qu'une version modifiée intégrant la fonction atan2.

A propos du nom des fonctions dans CaRMetal :
Le choix de l'utilisation des degrés et non des radian avec sin, cos, tan, etc. peut peut-être se comprendre dans un contexte scolaire, mais elle est en désaccord avec les autres logiciels de mathématiques et avec la plupart des langages de programmation.
N'aurait-il pas été plus judicieux de s'accorder avec ces derniers :

r en radians.
cos(r), sin(r), tan(r),
r = acos(x), r = asin(x), r = atan(x), r = atan2(y,x)

g en degrés.
cosd(g), sind(g), tand(g),
g = acosd(x), g = asind(x), g = atan(x), g = atan2d(y,x)

Cordialement.
Attachments
expression.zip
Modification de Expression.java dans le package rene.zirkel.expression pour y intégrer atan2.
(18.98 KiB) Downloaded 93 times

User avatar
alain974
Posts: 150
Joined: Sat Jun 13, 2009 9:08 am
Location: Réunion

Re: La fonction atan2 en natif dans CaRMetal

Post by alain974 » Wed Feb 09, 2011 10:27 am

stephrey wrote:Le choix de l'utilisation des degrés et non des radian avec sin, cos, tan, etc. peut peut-être se comprendre dans un contexte scolaire, mais elle est en désaccord avec les autres logiciels de mathématiques et avec la plupart des langages de programmation.
N'aurait-il pas été plus judicieux de s'accorder avec ces derniers
Non, dans la mesure où CaRMetal est censé être avant tout un logiciel pour le collège (et de plus en plus l'école primaire), qui a la chance de posséder accessoirement des fonctionnalités le rendant intéressant au lycée voire après. Une inversion des priorités reviendrait à vider complètement le logiciel de ce qui fait son intérêt. Donc il vaut mieux cibler les priorités dans cet ordre:

1: Tout ce qui peut améliorer la facilité à utiliser CaRMetal en classe (essentiellement collège) doit y être incorporé dès que possible.
2: En second lieu seulement, ce qui peut continuer à élargir le champ d'utilité du logiciel (géométrie supérieure, calcul formel, LaTeX ...) doit être exploré, mais bien sûr seulement si ça n'entre pas en conflit avec le premier point!

Or ici il y a conflit. Priorité doit être donnée au collège, donc on reste à rcos et rsin. En plus, changer la syntaxe des expressions poserait un problème de rétrocompatibilité des figures CaRMetal selon les versions du logiciel: J'ai des tas de vieilles figures que j'aimerais pouvoir continuer à ouvrir avec les versions futures du logiciel.


Par contre, rajouter atan2, pourquoi pas, je veux bien le faire si c'est utile (j'ai déjà ajouté 4 fonctions pour la 3.5.5). Ceci dit, en JavaScript il y a Math.atan2 qui marche très bien dans les CaRSCripts non dynamiques...

stephrey
Posts: 16
Joined: Thu Jan 20, 2011 3:51 pm
Location: Limoges

Post by stephrey » Wed Feb 09, 2011 11:24 am

Or ici il y a conflit. Priorité doit être donnée au collège, donc on reste à rcos et rsin. En plus, changer la syntaxe des expressions poserait un problème de rétrocompatibilité des figures CaRMetal selon les versions du logiciel: J'ai des tas de vieilles figures que j'aimerais pouvoir continuer à ouvrir avec les versions futures du logiciel.
Bon, d'accord, je m'incline. Mes CaRScripts feront la traduction entre la syntaxe de CaRMetal et celle de Maxima.
On pourrait créer les fonctions rarctan2 et arctan2 pour rester dans la logique de nommage propre à CaRMetal.
Ceci dit, en JavaScript il y a Math.atan2 qui marche très bien dans les CaRSCripts non dynamiques...
Dans les CaRScripts non dynamiques, je suis d'accord. Cependant, tout l'intérêt d'avoir la fonction rarctan2 est de pouvoir l'utiliser dans un contexte dynamique. Vouloir le faire par CaRScripts avec la fonction JavaScript Math.atan2 pourrait s'avérer beaucoup plus délicat et en tous cas bien plus difficile que ma solution initiale par ajout d'une fonction définie par l'utilisateur.

monique31
Posts: 373
Joined: Sat Nov 03, 2007 3:33 pm
Location: Toulouse

Re: La fonction atan2 en natif dans CaRMetal

Post by monique31 » Wed Feb 09, 2011 11:35 am

Non, dans la mesure où CaRMetal est censé être avant tout un logiciel pour le collège (et de plus en plus l'école primaire)
Tout à fait d'accord. Mais je me permets d'y ajouter un sentiment personnel : tel qu'il est maintenant CaRMetal est aussi spécialement bien adapté aux classes de lycée ! Voir tous les petits films sur le site ou sur MathemaTice, voir aussi tes articles, Alain, sur le site de la Réunion, ceux de Nathalie Carrié ... Autrement plus intuitif que bien d'autres même réputés :wink: (pour la question des vecteurs, des macros, des carscripts et bien d'autres ...).
Au lycée on utilise autant les degrés que les radians : cette double syntaxe est donc excellente pour se poser des questions.

User avatar
alain974
Posts: 150
Joined: Sat Jun 13, 2009 9:08 am
Location: Réunion

Post by alain974 » Wed Feb 09, 2011 2:05 pm

stephrey wrote:Vouloir le faire par CaRScripts avec la fonction JavaScript Math.atan2 pourrait s'avérer beaucoup plus délicat et en tous cas bien plus difficile que ma solution initiale par ajout d'une fonction définie par l'utilisateur.
En attendant il y a toujours la possibilité de simuler une telle fonction avec les if ou avec

Code: Select all

2*rarctan(x/(sqrt(x*x+y*y)+y))


ou encore avec angle360, on a le choix...

Ceci dit je suis pour l'ajout de atan2 et ratan2, j'attends d'autres opinions pour les mettre dans Expression.java.

stephrey
Posts: 16
Joined: Thu Jan 20, 2011 3:51 pm
Location: Limoges

Post by stephrey » Wed Feb 09, 2011 4:09 pm

Simuler rarctan2 avec

Code: Select all

2*rarctan(x/(sqrt(x*x+y*y)+y))
est inapproprié :
la division provoque un débordement au voisinage de la partie négative de l'axe des abscisses.
http://fr.wikipedia.org/wiki/Atan2
Attachments
rarctan2_definition.zir
Deux simulations de la fonction rarctan2
(2.51 KiB) Downloaded 91 times

monique31
Posts: 373
Joined: Sat Nov 03, 2007 3:33 pm
Location: Toulouse

Post by monique31 » Wed Feb 09, 2011 6:10 pm

alain974 wrote:avec

Code: Select all

2*rarctan(x/(sqrt(x*x+y*y)+y))

ou encore avec angle360, on a le choix...

Ceci dit je suis pour l'ajout de atan2 et ratan2, j'attends d'autres opinions pour les mettre dans Expression.java.
On a tellement le choix qu'il y a deux ans déjà, ayant eu besoin de cette notion pour les macros sur les coordonnées polaires j'avais utilisé une formule de mon cru probablement maladroite :

Code: Select all

rarccos(x(P1)/sqrt(x(P1)^2+y(P1)^2))*(2*(y(P1)>=0)-1)
Une formule qui a l'air de marcher même quand P1 est très près de 0 ou attaché à la partie négative de l'axe des abscisses (est-ce quand même une formule qui déborde ?)
Sûr que si à l'époque j'avais disposé de ratan2 je l'aurais utilisé, puisque dans une macro on utilise le moins possible d'initiaux.
Et peut-être que si un jour les complexes sont implémentés autrement que par ces petites macros cette fonction sera bien utile.
Reste à savoir s'il faut la mettre dans la liste de fonctions usuelles sous ce nom ; puisqu'en fait elle correspond à l'angle en coordonnées polaires.

monique31
Posts: 373
Joined: Sat Nov 03, 2007 3:33 pm
Location: Toulouse

Post by monique31 » Wed Feb 09, 2011 7:12 pm

Finalement, j'ai changé d'avis, et je me réponds à moi-même : mettre atan2 et ratan2 tels quels dans les expressions usuelles est une bonne idée. Ensuite il me faudra changer les macros sur les coordonnées polaires pour y intégrer ces formules. Excellente occasion avec cette macro d'apprendre aux élèves la correspondance entre les deux.
Pour les fonctions, par exemple, il y a aussi cette double approche par expression ou par macro.
D'autres avis ?

User avatar
alain974
Posts: 150
Joined: Sat Jun 13, 2009 9:08 am
Location: Réunion

Post by alain974 » Thu Feb 10, 2011 2:12 pm

C'est fait, les fonctions s'appelleront "atan2" et "ratan2" et apparaîtront sous la forme "atan2(,)" et "ratan2(,)" dans le menu. Elles sont (comme la modif proposée ci-dessus) définies en (0,0) et valent 0 dans ce cas.

Par contre atan2(y,x) ne donne rien dans une fonction alors que atan2(y+0,x) donne l'angle en degrés :?:

stephrey
Posts: 16
Joined: Thu Jan 20, 2011 3:51 pm
Location: Limoges

Post by stephrey » Thu Feb 10, 2011 11:37 pm

Elles sont (comme la modif proposée ci-dessus) définies en (0,0) et valent 0 dans ce cas.
Quelle est la bonne définition de atan2 ?
Si traditionnellement atan2(0,0) est non défini, la plupart implémentations informatiques définissent toujours atan2(0,0).

Pour Java et JavaScript, Math.atan2(0,0)==0.
Maxima répond quant à lui : atan2(0,0) is undefined.
Par contre atan2(y,x) ne donne rien dans une fonction alors que atan2(y+0,x) donne l'angle en degrés
Dans une fonction :
max(x+0,y)+min(x+0,y) fonctionne
max(x,y)+min(x,y) ne donne rien

Cela vient du fait que dans le deuxième cas, l'expression n'est pas considérée comme valide par CaRMetal.

Lorsque l'on rentre max(x,y)+min(x,y) en ayant choisi une fonction à deux variables, la méthode setExpressions est invoquée. Cela reviendrait, f1 étant une fonction utilisateur, à faire dans un CaRScript :

Code: Select all

ZC = Packages.eric.JZirkelCanvas.getCurrentZC()
CC = ZC.getConstruction();
CC.find("f1").setExpressions("x y","max(x,y)+min(x,y)");
Le code suivant nous montre qu'une nouvelle Expression est créée et que sa validité est vérifiée.

Code: Select all

...
package rene.zirkel.objects; 
...
public class UserFunctionObject extends ConstructionObject implements
MoveableObject, DriverObject, Evaluator {
...
	public void validate() {
		if (EY != null) {
			Valid = EY.isValid();
		} else {
			Valid = false;
		}
		if (Fixed && EXpos != null && EXpos.isValid()) {
			try {
				Xpos = EXpos.getValue();
			} catch (final Exception e) {
				Valid = false;
				return;
			}
		}
		if (Fixed && EYpos != null && EYpos.isValid()) {
			try {
				Ypos = EYpos.getValue();
			} catch (final Exception e) {
				Valid = false;
				return;
			}
		}
	}
	public void setExpressions(final String t, final String ey) {
		final StringTokenizer tok = new StringTokenizer(t);
		Var = new String[tok.countTokens()];
		X = new double[tok.countTokens()];
		int i = 0;
		while (tok.hasMoreTokens()) {
			Var[i++] = tok.nextToken();
		}
		EY = new Expression(ey, getConstruction(), this, Var);
		validate();
	}
...
}

Examinons donc le constructeur principal de la classe Expression :

Code: Select all

...
package rene.zirkel.expression;
...
public class Expression {
...
	public Expression(String s, final Construction c,
			final ConstructionObject o, final String var[],
			final boolean nocircles) {
		if (s.startsWith("+")) {
			ForcePlus = true;
			s = s.substring(1);
		}
		S = s;
		DL = new DepList();
		try {
			final ExpressionText t = new ExpressionText(s, c, o, DL, nocircles);
			t.setVar(var);
			E = TopExpression.scan(t);
			if (t.next() != 0) {
				throw new ConstructionException(Global.name("exception.superfluous"));
			}
			Valid = true;
		} catch (final Exception e) {
			Valid = false;
			ErrorText = (e.toString());
			// e.printStackTrace();
		}
	}
}
Pour une raison que je n'arrive pas à déterminer, l'examen de l'instruction E = TopExpression.scan(t) s'avérant difficile, la variable Valid est positionnée à false.

stephrey
Posts: 16
Joined: Thu Jan 20, 2011 3:51 pm
Location: Limoges

Post by stephrey » Fri Feb 11, 2011 9:12 am

Par contre atan2(y,x) ne donne rien dans une fonction alors que atan2(y+0,x) donne l'angle en degrés
Après une bonne nuit de sommeil, je reprends la lecture du code source de CaRMetal.
Je pense avoir identifié le problème :
Dans une fonction, le symbole "x" (resp. "y") a un double statut. S'il sert à récupérer les paramètres passés à la fonction, il ne faut pas oublier que comme ailleurs dans CaRMetal, il sert à invoquer la fonction qui retourne l'abscisse (resp. l'ordonnée) d'un point.
Ce double statut semble poser problème à l'analyseur syntaxique de CaRMetal.

Voilà, j'espère avoir pu donner un début d'explication qui devrait nous permettre de corriger ce qui me semble être une erreur de programmation.

stephrey
Posts: 16
Joined: Thu Jan 20, 2011 3:51 pm
Location: Limoges

Post by stephrey » Sat Feb 12, 2011 9:54 pm

Bonjour,
Par contre atan2(y,x) ne donne rien dans une fonction alors que atan2(y+0,x) donne l'angle en degrés
Le traitement de atan2 s'est greffé sur celui de min et max.

Dans la fonction scan de la classe FunctionExpression, ne sont examinés que deux cas pour le premier argument des fonctions min et max :
- soit il est de type ObjectExpression et on en déduit qu'il s'agit d'une fonction dont on va chercher un extremum dans un interval,
- soit il n'est pas de type ObjectExpression et on déduit qu'est recherché le minimum, ou le maximum, de deux valeurs.

On a oublié de traiter le cas où le premier argument est une variable x, y ou z. Dans ce cas, celui-ci est de type ObjectExpression, ce qui nous pose un problème.

Pour résoudre ce problème, il nous faudra déterminer si le premier argument est une variable.

Code: Select all

if (!(e instanceof ObjectExpression) ||(t.isVar(e.toString()))) {
				if (f == NMAX || f == NMIN || f == NATAN2) {
					if (t.next() != ',') {
						throw new ConstructionException(Global.name("exception.parameter"));
					}
					t.advance();
					final BasicExpression ee = TopExpression.scan(t);
					e = new FunctionExpression(f, e, ee);
				}
Attachments
bug_Expression.zip
(19.09 KiB) Downloaded 96 times

Post Reply