2  First Contact

Dieses Kapitel soll beim ‘Loslegen’ helfen. Es läßt viele Details weg und die Codebeispiele sind oft eher suboptimal.

2.1 Julia als Taschenrechner

Berechne \(\qquad 12^{1/3} + \frac{3\sqrt{2}}{\sin(0.5)-\cos(\frac{\pi}{4})\log(3)}+ e^5\)

12^(1/3) + 3sqrt(2) / (sin(.5) - cos(pi/4)*log(3)) + exp(5)
136.43732662344087

Man beachte:

  • Potenzen schreibt man a^b.
  • Die Konstante pi ist vordefiniert.
  • log() ist der natürliche Logarithmus.
  • Das Multiplikationszeichen a*b kann nach einer Zahl weggelassen werden, wenn eine Variable, Funktion oder Klammer folgt.

2.2 Die wichtigsten Tasten: Tab und ?

Man drücke beim Programmieren immer wieder die Tabulatortaste, sobald 2…3 Buchstaben eines Wortes getippt sind. Es werden dann mögliche Ergänzungen angezeigt bzw. ergänzt, wenn die Ergänzung eindeutig ist. Das spart Zeit und bildet ungemein:

lo  Tab
log
log2
lock
log1p
log10
local
logrange
lowercase
load_path
lowercasefirst
locate_package
pri  Tab
print
println
printstyled
primitive type

Die eingebaute Julia-Hilfe ?name zu allen Funktionen und Konstrukten ist sehr umfassend. Hier ein eher kurzes Beispiel:

?for
search: for nor xor floor foldr Core sort
for

for loops repeatedly evaluate a block of statements while iterating over a sequence of values.

The iteration variable is always a new variable, even if a variable of the same name exists in the enclosing scope. Use outer to reuse an existing local variable for iteration.

Examples

julia> for i in [1, 4, 0]
           println(i)
       end
1
4
0

2.3 Variablen und Zuweisungen

Variablen entstehen durch Zuweisung (assignment) mit dem Zuweisungsoperator = . Danach können sie in weiteren Anweisungen verwendet werden.

x = 1 + sqrt(5) 
y = x / 2
1.618033988749895

Im interaktiven Betrieb zeigt Julia das Ergebnis der letzten Operation an.

Hinweis

Zuweisungen sind keine mathematischen Gleichungen. Die Semantik des Zuweisungsoperators (Gleichheitszeichens) ist:

  • berechne die rechte Seite und
  • weise das Ergebnis der linken Seite zu.

Ausdrücke wie x + y = sin(2) sind daher unzulässig. Links darf nur ein Variablenname stehen.

2.4 Datentypen

Julia ist eine stark typisierte Sprache. Alle Objekte haben einen Typ. So gibt es unter anderem die Basistypen

  • Ganze Zahlen (integers),
  • Gleitkommazahlen (floating point numbers),
  • Zeichenketten (strings) und
  • Wahrheitswerte (booleans).

Den Typ einer Variablen kann man mit der Funktion typeof() ermitteln.

for x  (42, 12.0, 3.3e4, "Hallo!", true)
    println("x = ", x, " ..... Typ: ", typeof(x))
end
x = 42 ..... Typ: Int64
x = 12.0 ..... Typ: Float64
x = 33000.0 ..... Typ: Float64
x = Hallo! ..... Typ: String
x = true ..... Typ: Bool

Die Standard-Gleitkommazahl hat eine Länge von 64 Bit, entspricht also einer double in C/C++/Java.

Julia ist eine dynamisch typisierte Sprache. Variablen haben keinen Typ. Sie sind typlose Referenzen (Zeiger) auf Objekte. Wenn man vom „Typ einer Variablen“ spricht, meint man den Typ des Objektes, das der Variablen gerade zugewiesen ist.

x = sqrt(2)

println( typeof(x), " - Wert von x = $x" )

x = "Jetzt bin ich keine Gleitkommazahl mehr!"

println( typeof(x), "  - Wert von x = $x" )
Float64 - Wert von x = 1.4142135623730951
String  - Wert von x = Jetzt bin ich keine Gleitkommazahl mehr!

2.5 Druckanweisungen

Die Funktion println() unterscheidet sich von print() dadurch, dass sie am Ende einen Zeilenvorschub ausgibt.

print(y)
print("...die Zeile geht weiter...")
print("immernoch...")
println(y)
println("Neue Zeile")
println("Neue Zeile")
1.618033988749895...die Zeile geht weiter...immernoch...1.618033988749895
Neue Zeile
Neue Zeile

Beide Funkionen können als Argument eine Liste von strings und Variablen bekommen. Man kann Variablen auch in strings einbetten, indem man dem Variablennamen ein Dollarzeichen voranstellt (string interpolation).

x = 23
y = 3x + 5
zz = "Fertig!"
println("x= ", x, " ...und y= ", y, "...", zz)   # 1. Variante
println("x= $x ...und y= $y...$zz")              # Variante mit string interpolation
x= 23 ...und y= 74...Fertig!
x= 23 ...und y= 74...Fertig!

muss man einen backslash voranstellen. Wenn man einen backslash drucken will, muss man ihn verdoppeln.

println("Ein Dollar: 1\$ und drei backslashs: \\\\\\ ")
Ein Dollar: 1$ und drei backslashs: \\\ 

2.6 Funktionen

Funktionsdefinitionen beginnen mit dem Schlüsselwort function und enden mit dem Schlüsselwort end. In der Regel haben sie eine oder mehrere Argumente und geben beim Aufruf ein berechnetes Objekt mit der return-Anweisung zurück.

function hypotenuse(a, b)    # heute besonders umständlich
    c2 = a^2 + b^2
    c  = sqrt(c2)
    return c 
end
hypotenuse (generic function with 1 method)

Nach ihrer Definition kann die Funktion benutzt (aufgerufen) werden. Die in der Definition verwendeten Variablen a,b,c,c2 sind lokale Variablen und stehen außerhalb der Funktionsdefinition nicht zur Verfügung.

x = 3
z = hypotenuse(x, 4)
println("z = $z")
println("c = $c")
z = 5.0
UndefVarError: `c` not defined in `Main.Notebook`
Suggestion: check for spelling errors or missing imports.
Stacktrace:
 [1] top-level scope
   @ ~/Julia/23/Book-ansipatch/chapters/first_contact.qmd:206

Sehr einfache Funktionen können auch als Einzeiler definiert werden.

hypotenuse(a, b) = sqrt(a^2+b^2)
hypotenuse (generic function with 1 method)

2.7 Tests

Tests liefern einen Wahrheitswert zurück.

x = 3^2
x < 2^3
false

Neben den üblichen arithmetischen Vergleichen ==, !=, <, <= ,> ,>= gibt es noch viele andere Tests. Natürlich kann man das Ergebnis eines Tests auch einer Variablen zuweisen, welche dann vom Typ Bool ist. Die logischen Operatoren &&, || und Negation ! können in Tests verwendet werden.

test1 = "Auto" in ["Fahrrad", "Auto", "Bahn"]
test2 = x == 100 ||  !(x <= 30 && x > 8)
test3 = startswith("Lampenschirm", "Lamp") 
println("$test1 $test2 $test3")
true false true

2.8 Verzweigungen

Verzweigungen (bedingte Anweisungen) haben die Form

if <Test> 
    <Anweisung1> 
    <Anweisung2>
    ...
end

Ein else-Zweig und elseif-Zweige sind möglich.

x = sqrt(100)

if x > 20
    println("Seltsam!")
else
    println("OK")
    y = x + 3
end
OK
13.0

Einrückungen verbessern die Lesbarkeit, sind aber fakultativ. Zeilenumbrüche trennen Anweisungen. Das ist auch durch Semikolon möglich. Obiger Codeblock ist für Julia identisch zu folgender Zeile:

# Bitte nicht so programmieren! Sie werden es bereuen!
x=sqrt(100); if x > 20 println("Seltsam!") else println("OK"); y = x + 3 end
OK
13.0

Es wird dringend empfohlen, von Anfang an den eigenen Code übersichtlich mit sauberen Einrückungen zu formatieren!

2.9 Einfache for-Schleifen

zum wiederholten Abarbeiten von Anweisungen haben die Form

for  <Zähler> = Start:Ende
    <Anweisung1> 
    <Anweisung2>
    ...
end

Beispiel:

sum = 0
for i = 1:100
    sum = sum + i
end 
sum
5050

2.10 Arrays

1-dimensionale Arrays (Vektoren) sind eine einfache Form von Containern. Man kann sie mit echigen Klammern anlegen und auf die Elemente per Index zugreifen. Die Indizierung beginnt mit 1.

v = [12, 33.2,  17, 19, 22]
5-element Vector{Float64}:
 12.0
 33.2
 17.0
 19.0
 22.0
typeof(v)
Vector{Float64} (alias for Array{Float64, 1})
v[1] = v[4] + 10
v
5-element Vector{Float64}:
 29.0
 33.2
 17.0
 19.0
 22.0

Man kann leere Vektoren anlegen und sie verlängern.

v = []     # leerer Vektor
push!(v, 42)
push!(v, 13)
v
2-element Vector{Any}:
 42
 13
using REPL
function Tab(s)
    dc = map(x->x.name, REPL.doc_completions(s))
    l = filter(x->startswith(x,s), dc)
    println.(l)
    return   # return nothing, since broadcast println produces empty vector
end

 = |>     # https://docs.julialang.org/en/v1/manual/functions/#Function-composition-and-piping

pri = "pri";
pri  Tab
print
println
printstyled
primitive type