|
Lieber Clements, recht haben Sie -- in ihrem Beispiel, oder doch nicht? Schauen wir's uns an! Grundsätzlich sind alle Eingaben in Mathematica von der Form expr0[expr1,expr2,...] (wie Sie sich mit FullForm[], gegebenenfalls mit FullForm[Hold[]] überzeugen können). Diese werden nach dem von S.Wolfram in Kapitel 2.5 und im Anhang A.4 beschriebenen Verfahren evaluiert, sprich rekursiv umgeformt, solange bis nichts ändert. Umgeformt werden dabei alle Ausdrücke, für die in der Session mit Set, oder SetDelayed ausgeführte Definitionen als OwnValues, DownValues oder UpValues vorliegen, oder für die im Kern spezielle Behandlungen vorgesehen sind. Liegen aber solche Definitionen nicht vor, passiert gar nichts. Die Gestalt der Terme und der Evaluierungsmechanismus sagen nicht aus, wozu sie verwendet werden. (In der Tat werden sie für _alles_ verwendet, siehe 2.2.1 bei S.Wolfram) Vielfach stellt man mit Definitionen mathematische Funktionen dar. Man sollte sich aber sehr im klaren sein, daß ein Ausdruck f[x] in Mathematica als programmiersprachliches Objekt etwas völlig anderes ist als f(x) in C, Fortran u.a. Programmiersprachen. Letzteres bezeichnet einen Call zu einer Prozedur, pragmatisch den Ansprung eines Stückes Codes, der in der gebundenen Anwendung vorhanden sein muß, einschließlich der dynamischen Übergabe der Rücksprungadresse und der Parameter in einem festgelegten Format (in Fortran ist das eine Code-Adresse). Völlig anders in Mathematica. Hier wird nachgeschaut, ob Termersetzungsregeln anwendbar sind, wenn ja wird die Substitution ausgeführt, anderfalls passiert eben nichts. Betrachten wir ein Beispiel: In[1]:= a=c[1] /. c[1]->"eins" Out[1]= "eins" In[2]:= a Out[2]= "eins" In[3]:= ?c "Global`c" Wie wir sehen, hat a einen Wert bekommen, c aber nicht! c[1] war nur eine Form, die uns "eins" zur Zuweisung nach a getragen hat. Die Funktion von c[1] in diesem Zusammenhang ist nur: sie (1.) bezeichnet (links in Rule) das zu substituierende Objekt (rechts in Rule) und (2.) markiert (links in ReplaceAll) die Position an der das Substitut eingefügt werden soll. Nichts mehr! In[4]:= c[1]/. c[1]->"eins" Out[4]= "eins" In[5]:= c[1] Out[5]= c[1] hier ist der Wert nur nach In[6]:= %4 Out[6]= "eins" Out[4] getragen worden. Das ist nun genau die intendierte Funktion im Zusammenhang mit Solve, DSolve usw. In[1]:= DSolve[y''[x]==-w^2 y[x],y,x] Out[1]= {{y->(C[2] Cos[w #1]+C[1] Sin[w #1]&)}} In[2]:= f[1]=y /. %[[1]] /. {C[1]->0., C[2]->1.} Out[2]= 1. Cos[w #1]+0. Sin[w #1]& In[3]:= f[2]=y /.%%[[1]] /. {C[1]->1., C[2]->0.} Out[3]= 0. Cos[w #1]+1. Sin[w #1]& In[4]:= ?y "Global`y" In[5]:= Information[C] "C[i] is the default form for the ith constant of integration produced in \ solving a differential equation with DSolve." Attributes[C] = {Protected} Wir haben uns also zwei Lösungen besorgt, die Funktionen f[1] und f[2] mit denen wir jetzt beliebige Berechnungen z.B. Block[{w=Pi}, Plot[f[2][t],{t,-1,1}]] durchführen können. Weder y noch C[1] oder C[2] haben Werte bekommen, letzteren hätten wir auch überhaupt keine geben können! f selbst ist weder eine Funktion noch ein Array, sondern ein Symbol. Mit 1 und 2 'indizieren' wir im Ausdruck f[i] (ursprünglicher Wortsinn "zeigen auf") die eine oder die andere Lösungsfunktion. Mit dem Begriff "Array" muß man vorsichtig sein. In Mathematica ist dies ein (offizieller) technischer Term, der geschachtelte Strukturen mit Kopf List beschreibt, gilt dann noch die Restriktionen für gleiche Länge der Subtrukturen auf gleicher Ebene, heißt das Ding auch Matrix, ist der Wertetyp überall gleich, dann auch Tensor. Außer dem Kopf List, ist nichts besonderes daran. Jeder Ausdruck wird in Mathematica intern im Speicher als (jetzt allgemeine, inoffizielle Sprechweise) "Array" (d.h. als Wiederholungsstruktur im Speicher) abgelegt. expr0, d.h. der Kopf (genauer ein Pointer auf den Kopf) auf Position 0, die expr1, expr2, ... (resp. Pointer) auf den folgenden Plätzen 1, 2, ... Wird am Ausdruck strukturell etwas verändert, z.B. durch Append, muß dieses gesamte "Array" kopiert werden, um noch Platz für das hinzukommende Element zu schaffen. Deswegen sollte man mit Append, Drop etc. bei _sehr_ großen Strukturen (bei tausenden von Elementen) vorsichtig sein. Andererseits aber arbeiten die Funktionen Map, Thread, Transpose, Part, Inner, Outer, etc. direkt auf diesen Strukturen (bzw. manipulieren sie direkt) und sind deswegen phantastisch schnell. Jedes Element eines Ausdruckes und jeder Unterausdruck läßt sich mit der Funktion Part der Struktur entnehmen ("indizieren"), d.h. Part ist die Manövrierfunktion auf den gestuften (eindimensionalen) Pointer-Arrays der Implementierung. So gibt In[10]:= f[2][[1,2,2,0]] Out[10]= Sin Nur wenn die Struktur flach ist, bzw. auf einer Ebene, kann man das mit der Indizierung eines Arrays in C oder in Fortran vergleichen, keinesfalls aber bei gestuften Indizierungen! Das ist genauso syntaktischer Zucker wie bei den Funktionen oben! Die Semantik freilich ist oft -- aber nicht immer -- dieselbe. __________ Ich wiederhole hier meine Warnung vor reeller "Indizierung" in Ausdrücken der Form c[i]. Das abgegebene Beispiel sollte eigentlich schlagend sein. Ich danke aber Roman E. Mäder für seinen angefügten Hinweis, der mir erst klarmachte, daß c[1.] _unbeabsichtigt_ entstanden sein könnte. Dann heißt es natürlich dort zu feilen, wo die Reals reinkamen. Was jetzt Ihr Beispiel betrifft, lieber Clemens Clemens Frey schrieb: > > Hallo! > > Nur ein kleiner Kommentar zur Holzweg-Bemerkung (s.u.), ganz unabhaengig > vom urspuenglichen Problem. Es ist doch ueberhaupt nicht abwegig, in MMA > etwa Spezialfaelle einer Funktion so zu definieren : > > c[x_]/; x<0 = -1.; > c[x_]/; x>0 = 1.; > c[0.] = c[0] = 0.; > Betrachten wir erstmal: In[1]:= c[x_]:=-1./; x<0; c[x_]:= 1./;x>0; c[0]=0.; In[2]:= epsi=0.+10^-15 Out[2]= \!\(1.`*^-15\) In[3]:= {c[epsi],c[-epsi],c[0],c[epsi^3],c[-epsi^3],c[0.]} Out[3]= {1.,-1.,0.,1.,-1.,c[0.]} In[4]:= c[N[Sin[10.^-50000],50000]] Out[4]= 1. also der kleinstmögliche positive relle Wort gibt eins (wie es sich gehört), aber für die reelle 0. (¿was ist das genau?) gibt es keinen Wert, denn 0. ist nicht größer als 0, nicht kleiner als 0 und c[0.] matched nicht auf das Muster c[0] -- alles sonnenklar, also, die "Funktion" hat ein Loch. Wie stopfen? Versuchen wir's nach Ihrem Vorschlag: In[1]:= c[x_]:=-1./; x<0; c[x_]:= 1./;x>0; c[0]=0.; c[0.]="hoppla"; In[2]:= epsi=0.+10^-15 Out[2]= \!\(1.`*^-15\) In[3]:= {c[epsi],c[-epsi],c[0],c[epsi^3],c[-epsi^3],c[0.]} Out[3]= {1.,-1.,0.,1.,-1.,"hoppla"} In[4]:= c[N[Sin[10.^-50000],50000]] Out[4]= "hoppla" In[5]:= N[Sin[10.^-20000],50000]>0 Out[5]= True Was ist da passiert? c[0.] bekommt den Wert, den wir vorgesehen hatten, aber der kleinste positve Wert ist zwar nicht gleich Null, bekommt aber den Wert für reell Null?? (im Gegensatz zum alten Programm oben, wo dieser richtig berechnet wurde) Jetzt kommen wir zu einer etwas trüberen Seite von Mathematica. Das Rätsel löst sich, wenn wir uns die Definition für c anschauen: In[6]:= ?c "Global`c" c[0] = 0. c[0.] = "hoppla" c[x_] := -1. /; x < 0 c[x_] := 1. /; x > 0 Aha, es kommt gar nicht zur Abfrage x>0, sondern c[N[Sin[10.^-20000],50000]] matched c[0.] (Warum das so ist, muß man wohl bei Wolfram Research nachfragen!) Deswegen, meine ich, die korrekte Variante deiner Funktion ist In[9]:= Clear[c] In[10]:= c[x_]:=-1. /; x<0; c[x_]:= 1. /;x>0; c[x_]:= 0. /;x==0 In[11]:= ?c "Global`c" c[x_] := -1. /; x < 0 c[x_] := 1. /; x > 0 c[x_] := 0. /; x == 0 In[12]:= {c[epsi],c[-epsi],c[0],c[epsi^3],c[-epsi^3],c[0.]} Out[12]= {1.,-1.,0.,1.,-1.,0.} In[13]:= c[N[Sin[10.^-50000],50000]] Out[13]= 1. Ceterum Censeo! > Das hat doch nichts mit "Indizierung" irgendeines Arrays zu tun (wir sind > hier nicht in C!!), auch wenn man das auch damit machen koennte; eine > solche Methode bietet sich meiner Meinung z.B. an, falls > man heufig einzelne Elemente eines grossen Arrays aendern muss und > verhindern will, das jedesmal das ganze Array wieder ausgewertet > wird. Weiteres Stichwort: Assoziative Arrays etc. > Der Vorsatz ist geklärt, der Nachsatz ist ein Trick zur Verbesserung der Performance wie er z.B. bei David B. Wagner: Power Programming with Mathematica: The Kernel beschrieben ist. [Anmerkung: Ich wollte natürlich niemanden mit "Holzweg" beleidigen, aber ich will jeden von einem offensichtlichen Irrweg abhalten!] Beste Grüße Hartmut Wolf |