asin, acos und atan mit dereferenzierten Variablen

asin, acos und atan mit dereferenzierten Variablen

am 17.11.2007 10:01:16 von Markus Hochholzer

Hallo zusammen,

kann mir jemand erklären, warum folgendes Skript nicht funktioniert.
$A->[2]->[0] enthält den Wert -0.9999859

#!/usr/bin/perl -w
use strict;

use constant PI => 4 * atan2(1, 1);
use Math::Trig;

my $Wy = ${$A->[2]}[0];
my $Ryrad = Math::Trig->asin($Wy);

In der Routine von asin in Complex.pm steht nun folgendes:
my ($z) = $_[0];

Ich weiß mittlerweile auch, daß es nicht geht, weil sozusagen der Typ
der Variable und nicht der Wert übergeben wird.
Aber mit my $Wy = ${$A->[2]}[0]; habe ich doch dereferenziert. Oder
nicht? Wie dereferenziert man den Wert einer zweidimensionalen Matrix
richtig?

Wenn ich in Complex.pm
my ($z) = $_[1];
verwende, dann funktioniert es.


Gruß Markus

Re: asin, acos und atan mit dereferenzierten Variablen

am 17.11.2007 18:02:52 von Frank Seitz

Markus Hochholzer wrote:

> kann mir jemand erklären, warum folgendes Skript nicht funktioniert.
> $A->[2]->[0] enthält den Wert -0.9999859
>
> #!/usr/bin/perl -w
> use strict;
>
> use constant PI => 4 * atan2(1, 1);
> use Math::Trig;
>
> my $Wy = ${$A->[2]}[0];
> my $Ryrad = Math::Trig->asin($Wy);

Das Programm läuft nicht:
Global symbol "$A" requires explicit package name [...]

Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel

Re: asin, acos und atan mit dereferenzierten Variablen

am 18.11.2007 16:42:28 von sheinrich

On Nov 17, 10:01 am, Markus Hochholzer wrote:
> Hallo zusammen,
>
> kann mir jemand erklären, warum folgendes Skript nicht funktioniert.
> $A->[2]->[0] enthält den Wert -0.9999859
Bist du sicher?
Mache mal ein "print $A->[2]->[0];"

Wenn die Ausgabe wirklich -0.9999859 sein sollte, dann brauchst du
nichts zu dereferenzieren.

Wenn es stimmt, heisst das:
$A =3D [
[...],
[...],
[-0.9999859, ...],
[...],
...
];
Und deine Dereferenzierung sollte, wenn auch unnoetig, richtig sein.

Verwende dann einfach genau diesen Ausdruck bei der Zuweisung oder
direkt bei der Uebergabe als Realzahl.
print asin($A->[2]->[0]);

>
> #!/usr/bin/perl -w
> use strict;
>
> use constant PI =3D> 4 * atan2(1, 1);
> use Math::Trig;
>
> my $Wy =3D ${$A->[2]}[0];
> my $Ryrad =3D Math::Trig->asin($Wy);
>
> In der Routine von asin in Complex.pm steht nun folgendes:
> my ($z) =3D $_[0];
>
> Ich weiß mittlerweile auch, daß es nicht geht, weil sozusagen der Typ
> der Variable und nicht der Wert übergeben wird.
Nicht der Typ; die Referenz.
Das ist gewissermassen ein Pointer auf die Speicherstelle, der
gleichzeitig den Typ beinhaltet (kennt).
Hast du Warnungen erhalten? Welche?

> Aber mit my $Wy =3D ${$A->[2]}[0]; habe ich doch dereferenziert. Oder
> nicht? Wie dereferenziert man den Wert einer zweidimensionalen Matrix
> richtig?
>
> Wenn ich in Complex.pm
> my ($z) =3D $_[1];
> verwende, dann funktioniert es.
Das deutet daraufhin, dass du anstelle eines Scalars ein Array
uebergibst, an dessen 2. Stelle der gewuenschte Wert steht (falls denn
das Ergebnis der Erwartung entspricht).

Das hiesse, dass deine Matrix mehr als 2 Dimensionen haette und dass
dein Wert eigentlich auch als ${${$A->[2]}[0]}[1] zu finden sein
muesste.

$A =3D [
irgendwas,
irgendwas,
[[irgendwas, -0.9999859, ...], ...],
irgendwas,
...
];

Wie baust du die Matrix denn auf?
Wenn du immer eine direkte Adressierung ueber Indizes verwenden
kannst, ist die Sache IMHO am einfachsten:
$A->[$x-1]->[$y-1] =3D $xy;

Gruesse
von Steffen

BTW: In dem von dir zitierten Math::Complex habe ich gesehen, dass
dort fuer Realzahlen <=3D 1 nur die perl eingebauten Funktionen
verwendet werden:
>perl -e "print atan2(-0.9999859, sqrt(1 - -0.9999859 * -0.9999859));"
-1.56548595333625

Re: asin, acos und atan mit dereferenzierten Variablen

am 22.11.2007 13:01:18 von Markus Hochholzer

sheinrich@my-deja.com schrieb:
> On Nov 17, 10:01 am, Markus Hochholzer wrote:
>> Hallo zusammen,
>>
>> kann mir jemand erklären, warum folgendes Skript nicht funktioniert.
>> $A->[2]->[0] enthält den Wert -0.9999859
> Bist du sicher?
> Mache mal ein "print $A->[2]->[0];"

Ich erhalte den Wert -0.9999859

> Verwende dann einfach genau diesen Ausdruck bei der Zuweisung oder
> direkt bei der Uebergabe als Realzahl.
> print asin($A->[2]->[0]);

Dann erhalte ich eine Fehlermeldung: "Argument "Math::Trig" isn't
numeric in abs at C:/Perl/lib/Math/Complex.pm line 977."


>> Ich weiß mittlerweile auch, daß es nicht geht, weil sozusagen der Typ
>> der Variable und nicht der Wert übergeben wird.
> Nicht der Typ; die Referenz.
> Das ist gewissermassen ein Pointer auf die Speicherstelle, der
> gleichzeitig den Typ beinhaltet (kennt).
> Hast du Warnungen erhalten? Welche?

Nein, es wird eine 0 zurückgegeben. Keine Warnung oder Fehlermeldung.

>> Aber mit my $Wy = ${$A->[2]}[0]; habe ich doch dereferenziert. Oder
>> nicht? Wie dereferenziert man den Wert einer zweidimensionalen Matrix
>> richtig?
>>
>> Wenn ich in Complex.pm
>> my ($z) = $_[1];
>> verwende, dann funktioniert es.
> Das deutet daraufhin, dass du anstelle eines Scalars ein Array
> uebergibst, an dessen 2. Stelle der gewuenschte Wert steht (falls denn
> das Ergebnis der Erwartung entspricht).
>
> Das hiesse, dass deine Matrix mehr als 2 Dimensionen haette und dass
> dein Wert eigentlich auch als ${${$A->[2]}[0]}[1] zu finden sein
> muesste.

Da erhalte ich eine Fehlermeldung:" Can't use string ("-0.9999859") as
an Array ref while "strict ref" is in use at ...

> Wie baust du die Matrix denn auf?
> Wenn du immer eine direkte Adressierung ueber Indizes verwenden
> kannst, ist die Sache IMHO am einfachsten:
> $A->[$x-1]->[$y-1] = $xy;

In meinem Modul myMatrix.pm werden 2 Matrizen multipliziert.
sub Multiplikation {
my $class = shift;
my $M1 = shift;
my $M2 = shift;
my $R = [];

return 0 if ($#{$M1->[0]} != $#$M2);

for (my $i=0; $i<=$#$M1; $i++){
for (my $j=0; $j<=$#{$M2->[0]}; $j++){
for (my $k=0; $k<=$#{$M1->[0]}; $k++){
$R->[$i]->[$j] += $M1->[$i]->[$k] * $M2->[$k]->[$j];
}
}
}
return $R;
}
Im Hauptprogramm wird dies mittels
my $A = myMatrix->Multiplikation($M1,$M2); aufgerufen

$A array
|->[0] array
| |->[0] scalar 0.004468
| |->[1] scalar 0.002326
| |->[2] scalar -0.99998
|
|->[1] array
| |->[0] scalar -0.00286
| |->[1] scalar -0.99999
| |->[2] scalar -0.00233
|
|->[2] array
|->[0] scalar -0.99998
|->[1] scalar 0.002873
|->[2] scalar -0.00446

Aus der Rotationsmatrix $A will ich dann die Winkel errechnen.

Gruß Markus

Re: asin, acos und atan mit dereferenzierten Variablen

am 23.11.2007 14:26:52 von sheinrich

OK, die Loesung naht!

On Nov 22, 1:01 pm, Markus Hochholzer wrote:
> sheinr...@my-deja.com schrieb:
>
> > On Nov 17, 10:01 am, Markus Hochholzer wrote:
> >> Hallo zusammen,
>
> >> kann mir jemand erklären, warum folgendes Skript nicht funktioniert.
> >> $A->[2]->[0] enthält den Wert -0.9999859
> > Bist du sicher?
> > Mache mal ein "print $A->[2]->[0];"
>
> Ich erhalte den Wert -0.9999859
>
> > Verwende dann einfach genau diesen Ausdruck bei der Zuweisung oder
> > direkt bei der Uebergabe als Realzahl.
> > print asin($A->[2]->[0]);
>
> Dann erhalte ich eine Fehlermeldung: "Argument "Math::Trig" isn't
> numeric in abs at C:/Perl/lib/Math/Complex.pm line 977."

Mir ist jetzt erst aufgefallen, dass die Syntax aus dem 1. Posting
anscheinend nicht stimmt:
Falsch
Math::Trig->asin($Wy);

Richtig:
asin($Wy);

oder auch (falls der Name nicht importiert worden waere):
Math::Trig::asin($A->[2]->[0]);

Es handelt sich um eine statische, bzw. Klassenmethode
Mit der Pfeilsyntax wird aber als 1. Parameter eine Referenz
uebergeben.
Ueblicherweise auf das Objekt, in deinem Fall auf die Klasse.

...

>
> >> Wenn ich in Complex.pm
> >> my ($z) =3D $_[1];
> >> verwende, dann funktioniert es.
> > Das deutet daraufhin, dass du anstelle eines Scalars ein Array
> > uebergibst, an dessen 2. Stelle der gewuenschte Wert steht (falls denn
> > das Ergebnis der Erwartung entspricht).
Das hatte ich noch richtig gesehen, der 1. Wert war die Klasse.

>
> > Das hiesse, dass deine Matrix mehr als 2 Dimensionen haette und dass
> > dein Wert eigentlich auch als ${${$A->[2]}[0]}[1] zu finden sein
> > muesste.
.. aber meine Folgerung war falsch :-)

..
>
> In meinem Modul myMatrix.pm werden 2 Matrizen multipliziert.
> sub Multiplikation {
> my $class =3D shift;
> my $M1 =3D shift;
> my $M2 =3D shift;
> my $R =3D [];
>
> return 0 if ($#{$M1->[0]} !=3D $#$M2);
>
> for (my $i=3D0; $i<=3D$#$M1; $i++){
> for (my $j=3D0; $j<=3D$#{$M2->[0]}; $j++){
> for (my $k=3D0; $k<=3D$#{$M1->[0]}; $k++){
> $R->[$i]->[$j] +=3D $M1->[$i]->[$k] * $M2->[$k]->[$j];
> }
> }
> }
> return $R;}
>
..

Uebrigens:
Du kannst $A->[2]->[0] oder aehnliches immer auch als $A->[2][0]
schreiben.
Bei tief strukturierten Daten reicht der 1. Pfeil, weil von dort bis
zum Wert nur noch Referenzen vorliegen koennen.

Steffen

Re: asin, acos und atan mit dereferenzierten Variablen

am 23.11.2007 18:19:29 von Ferry Bolhar

Steffen:

> Mir ist jetzt erst aufgefallen, dass die Syntax aus dem 1. Posting
> anscheinend nicht stimmt:
> Falsch
> Math::Trig->asin($Wy);
>
> Richtig:
> asin($Wy);
>
> oder auch (falls der Name nicht importiert worden waere):
> Math::Trig::asin($A->[2]->[0]);
>
> Es handelt sich um eine statische, bzw. Klassenmethode

Ich würde sagen, es handelt sich um gar keine Methode, sondern
einfach um ein gewöhnlichen Funktionsaufruf.

> Mit der Pfeilsyntax wird aber als 1. Parameter eine Referenz
> uebergeben.
> Ueblicherweise auf das Objekt, in deinem Fall auf die Klasse.

Nein.

Mit der Pfeilsyntax wird das übergeben, "was vor dem Pfeil steht".

1) Entweder ein Skalar, der eine Objekt- (Klassen-) Referenz
enthält, dann spricht man von einer Instanzenmethode, weil der
Skalar mit bless() als "Instanz" der jeweiligen Klasse markiert wurde:

bless my $x = [], 'Hallo';
$x->hugo(); # Ruft Hallo::hugo($x) auf

2) Oder ein Skalar, der die gewünschte Klasse als Stringkonstante
enthält, dann spricht man von einer Klassenmethode:

my $x = 'Hallo';
$x->hugo(); # Ruft Hallo::Hugo('Hallo') auf

3) Oder gleich direkt durch Angabe der Klasse als Stringliteral:

'Hallo'->hugo(); # Detto

wobei der Parser hier in seiner Großmut das Weglassen der
Quotes um den Klassennamen erlaubt.

Aus dem Ausdruck

$skalar->function();

geht also noch nicht hervor, ob eine Klassen- oder Instanzen-
methode aufgerufen wird und ob eine Referenz oder ein String
als erstes Argument übergeben wird!

Wichtig: bei Methodenaufrufen (egal ob Klassen- oder Instanz-
methoden) greift das Vererbungsprinzip (@ISA - Array), bei
Funktionsaufrufen (also Konstrukte ohne Pfeil wie

Math::Trig::asin($A->...);

) nicht.

> Uebrigens:
> Du kannst $A->[2]->[0] oder aehnliches immer auch als $A->[2][0]
> schreiben.
> Bei tief strukturierten Daten reicht der 1. Pfeil, weil von dort bis
> zum Wert nur noch Referenzen vorliegen koennen.

Ja. Ich persönlich schätze allerdings die Form mit allen Pfeilen mehr,
weil sie deutlicher macht, dass es sich doch nur um Referenzen und
nicht etwa um multi-dimensionale Arrays bzw. Hashes handelt.
Aber das ist Geschmackssache.

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: ferdinand.bolhar-nordenkampf@wien.gv.at