Berechnung der Determinante einer NxN Matrix in MIPS Assembler

6. Februar 2010
.data

dim:
#.word 2
#.word 3
#.word 4
.word 5
#.word 10

matrix:
#2x2-Martrix; solution = -2
#.word 3, 4, 5, 6
#3x3-Matrixx; solution = 4
#.word 3, 4, 5, 9, 4, 9, 1, 2, 2
#4x4-Matrix; solution = -19
#.word 3, 4, 5, 9, 4, 9, 1, 2, 2, 1, 3, 5, 7, 9, 3, 5
#solution = 0
.word 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25
#.word -2, 1, 1, -2, -1, -1, -1, 3, -2, -3, 0, -1, -1, -4, -5, -5, 3, 2, -4, 1, 1, 1, 0, 3, 2, 0, 3, 3, 2, 0, 2, -3, 0, -1, 4, -1, -2, -3, 0, -1, 2, -3, -3, -5, -3, -5, -3, -1, -5, 3, 0, -5, 0, -5, -5, -1,  2,  1, -4, -1, -5, -4,  1,  1, -4,  2,  3,  4, -3, -1, 1, -2,  0, -3,  1, -5,  4,  3, -1, -4, -5,  2, -5, -2, -3, -3,  3, -2,  1, -3, 1, -1, -3,  2,  0, -5,  3,  2,  3, -5

det:    .asciiz "Die Determinante ist: "
###############################################################################

.text

main:
###################################
###################################
#Hier soll das Programm stehen
#Das Ergebnis muss am Ende in $s6 stehen.

    addi    $s7, $0, 0x10040000 # initialize default heap pointer
 
    la      $a0, matrix
    lw      $a1, dim
    jal     calcDet
    addi    $s6, $v0, 0

    j       ende

###################################
# Calculates the determinante of a NxN matrix.
# expects:  adress of array with N^2 elements in $a0
#           dimension of matrix in $a1
# returns det. of given matrix in $v0
###################################
# Documentation
# $a0   -> matrix
# $a1   -> dim
# ----------------
# $s0   -> sum of det. of matrixes
calcDet:
    # if
    slti    $t0, $a1, 2         # if $a1(=dim) < 2
    beq     $0, $t0, calcDetIf  # jump to the if part
                                # if $t0 == $t1(=1) or
                                # if 2 < dim
    # else
    lw      $v0, 0($a0)
    jr      $ra                 # jump back to caller

calcDetIf:                      # The if part
    # reduce maxtrix and call recursive for each
    # reduced matrix
    addi    $sp, $sp, -4        # get some space on stack
    sw      $ra, 0($sp)         # store return adress in stack
   
    addi    $s0, $0, 0          # initialize $s0 (sum) with 0
    addi    $t0, $0, 0          # initialize $t0 (i) with 0
   
calcDetLoop:                    # loop over all sub-matrixes
    beq     $t0, $a1, calcDetLoopDone
                                # while $t0(=i) != $a1(=dim)

    addi    $sp, $sp, -16       # get some space on stack
    sw      $s0, 0($sp)         # store sum
    sw      $t0, 4($sp)         # store $t0 (i)
    sw      $a0, 8($sp)         # store $a0
    sw      $a1, 12($sp)        # store $a1

                                # dont need to copy any adress
                                # in $a0 because its already there
                                # dont need to copy any dimension
                                # of matrix in $a1 because its already there
    addi    $a2, $t0, 0         # copy i into $a2
    jal     reduceMatrix        # jump to reduceMatrix
   
    addi    $a0, $v0, 0         # copy result adress of reduceMatrix
                                # into argument register for recursive call
    sub     $a1, $a1, 1         # $a1 = dim - 1
    jal     calcDet             # call myself recursively
   
    lw      $a1, 12($sp)        # load $a1
    lw      $a0, 8($sp)         # load $a0
    lw      $t0, 4($sp)         # load $t0 (i)
    lw      $s0, 0($sp)         # load sum
    addi    $sp, $sp, 16        # clean up the stack

    addi    $t2, $0, 1          # initialise pow(er) with 1
    and     $t1, $t0, 1         # $t1 = $t0 & 0x00000001
    beq     $t1, $0, calcDetLoopJump
                                # skip one line, if $t0 % 2 = 1
    addi    $t2, $0, -1         # set power to -1
calcDetLoopJump:               

    addi    $t1, $0, 4          # $t1 = 4 (because one word = 4 bytes)
    mult    $t0, $t1            # i * $t1(=4)
    mflo    $t3                 # get result in $t3
    add     $t3, $a0, $t3       # add calulated offset to start adress of matrix
    lw      $t3, 0($t3)         # load value at calulated adress

    mult    $t2, $t3            # power * (i-th element in matrx (always in first row))
    mflo    $t4                 # get result in $t4
    mult    $t4, $v0            # multiply calcDet-result with calculated stuff
    mflo    $t4                 # get result in $t4
    add     $s0, $s0, $t4       # add to sum

    addi    $t0, $t0, 1         # $t0++ or i++

    j       calcDetLoop


calcDetLoopDone:                # loop finished, calculated all matrixes
    addi    $v0, $s0, 0         # copy sum into return register

    lw      $ra, 0($sp)         # load return adress from stack
    addi    $sp, $sp, 4         # get some space on stack

    jr      $ra
###################################


###################################
# Extracts _one_ (N-1) matrix from a
# NxN matrix. The argument
# $a2 says which (N-1) matrix should
# be returned.
# expects:  adress of array with N^2 elements in $a0
#           dimension of matrix in $a1
#           index of the smaller matrix (0-based) in $a2
# returns adress of (N-1) matrix in $v0
###################################
# Documentation
# $a0   -> matrix
# $a1   -> dim
# $a2   -> index of matrix that should be returned
# ----------------
# $s0   -> dim - 1
# $s1   -> counter for the current position in the SOURCE matrix
# $s2   -> counter for the current position in the TARGET matrix
reduceMatrix:
    addi    $s0, $a1, -1        # $s0 = dim - 1
    mult    $s0, $s0            # $s0*$s0 or
                                # (N-1)^2 or (dim-1)^2
                                # is also the size of the
                                # new matrix
    mflo    $t1                 # get result into $t1
                                # $t1 contains now the number of words required
    addi    $s1, $a0, 0         # copy start adress of source matrix in $s1
    addi    $s2, $s7, 0         # save current position of heap pointer in $s2
    addi    $v0, $s7, 0         # copy target array adress in return register
    addi    $t0, $0, 4          # set $t0 = 4
    mult    $t1, $t0            # multiply $t0(=4) * $t1(=(dim-1)^2)
                                # -> amount of necessary bytes
    mflo    $t0                 # copy result in $t0
    add     $s7, $s7, $t0       # get (N-1)^2 space of heap

    addi    $t0, $0, 4          # set $t0 = 4
    mult    $a1, $t0            # $a1(=dim)*$t0(=4)
                                # number of bytes that must be skipped to
                                # skip the first row of source matrix
    mflo    $t0
    add     $s1, $s1, $t0       # skip dim-elements or
                                # skip the first row of source matrix
    addi    $t0, $s0, 0         # initialize counter for loop 1; used as i
    add     $t2, $t0, $a2       # $t2 = $t0 + $a2 or
                                # $t2 = i + index
reduceMatrixLoop1:              # loop 1
    beq     $t2, $t0, reduceMatrixLoop1Done
                                # while index != i

    lw      $t1, 0($s1)         # load next entry from source matrix in $t1
    sw      $t1, 0($s2)         # store the entry in the target matrix
    addi    $s1, $s1, 4         # increase pointer $s1 = $s1 + 4
    addi    $s2, $s2, 4         # increase pointer $s2 = $s2 + 4

    addi    $t0, $t0, 1         # $t0 = $t0 + 1 or
                                # $t0++ (i++)
    j       reduceMatrixLoop1   # jump up to the beginning of the loop
reduceMatrixLoop1Done:          # endloop 1
reduceMatrixLoop2:              # loop 2
    mult    $a1, $a1
    mflo    $t1
    beq     $t0, $t1, reduceMatrixLoop2Done
                                # while i < dim^2

    addi    $s1, $s1, 4         # skip one element in SOURCE matrix
    addi    $t0, $t0, 1         # $t0 = $t0 + 1 or
                                # $t0++ or i++
   
    mult    $a1, $a1            # $a1^2 or dim^2
    mflo    $t2                 # get the result in $t2
    sub     $t2, $t2, 1         # sub 1 from $t2, because I want to compare
                                # it with $t0 (0-based) or
                                # (dim^2)-1
    sub     $t2, $t2, $t0       # $t2-$t0 or (dim^2)-1-i
    # if
    slt     $t3, $t2, $s0       # (dim^2)-1-i < dim-1 or
                                # if $t3 == 1, you reached the last
                                # row and already skipped
    beq     $t3, $0, reduceMatrixLoop2Else
                                # jumps, if (dim-1)^2 - i < dim - 1 is false
                                # in human words: if the programm
                                # is NOT in the last row of the source matrix
    # if case
    # copy the last elements of source into target and exit function! :)
    mult    $a1, $a1            # dim^2
    mflo    $t2                 # get result in $t2
reduceMatrixLoop2Loop1:
    beq     $t2, $t0, reduceMatrixLoop2Done
                                # jump if dim^2-1 == i or jump if
                                # end of source matrix is reached
   
    lw      $t1, 0($s1)         # load next entry from source matrix in $t1
    sw      $t1, 0($s2)         # store the entry in the target matrix
    addi    $s1, $s1, 4         # increase pointer $s1 = $s1 + 4
    addi    $s2, $s2, 4         # increase pointer $s2 = $s2 + 4

    addi    $t0, $t0, 1         # $t0 = $t0 + 1 or
                                # $t0++ or i++
    j       reduceMatrixLoop2Loop1
                                # jump up again, because its a loop!

    j       reduceMatrixLoop2Endif
                                # leave if case
                                # never used because if loop is finished
                                # it will jump to the end of the function

reduceMatrixLoop2Else:          # else case
    # copy dim - 1 elements
    add     $t2, $t0, $s0       # $t2 = $t0(=i) + $s0(=dim-1)
reduceMatrixLoop2ElseLoop:
    beq     $t2, $t0, reduceMatrixLoop2
                                # if $t2 = $t0 jump to main loop

    lw      $t1, 0($s1)         # load next entry from source matrix in $t1
    sw      $t1, 0($s2)         # store the entry in the target matrix
    addi    $s1, $s1, 4         # increase pointer $s1 = $s1 + 4
    addi    $s2, $s2, 4         # increase pointer $s2 = $s2 + 4
   
    addi    $t0, $t0, 1         # $t0 = $t0 + 1 or
                                # $t0++ or i++
    j       reduceMatrixLoop2ElseLoop
                                # jump up to the beginning of the loop

reduceMatrixLoop2Endif:         # endif


    addi    $t0, $t0, 1         # $t0 = $t0 + 1 or
                                # $t0++ or i++
    j       reduceMatrixLoop2   # jump up to the beginning of the loop
reduceMatrixLoop2Done:          # endloop 2
    jr      $ra                 # jump to caller function
                                # return value ($v0) is set at beginning
                                # of this function
###################################

###################################
###################################

ende:
#Ausgabe

la $a0 det
li $v0 4
syscall

move $a0, $s6
li $v0, 1
syscall

###################################
#Ende
li $v0, 10
syscall

Dieser Assemblercode kann die Determinante einer NxN Matrix berechnen. Dabei wird die NxN-Matrix mit Hilfe des Laplaceschen Entwicklungssatzes in N N-1xN-1-Matrixen zerlegt (eine 4×4-Matrix wird in 4 3×4-Matrixen zerlegt, usw).

Das Programm funktioniert leider nicht für “große” Matrixen (z.B. 10×10), weil das Programm dann aus dem Heap raus schreibt. Aber für Matrixen bis 5×5 funktioniert es definitiv, eventuell auch für Größere, das habe ich aber nicht getestet.

Sende Artikel als PDF an PDF

Zooma Mitschnitte zum Download

23. Januar 2010

Hier gibt es alle Zooma Mitschnitte zum Download!

Sende Artikel als PDF an PDF

Parallelität

17. Januar 2010

Parallelität bedeutet, dass man Aufgaben oder Teilaufgaben parallel – also gleichzeitig – bearbeitet. Dabei gibt es zwei grundsätzliche Arten:

  • Räumliche Parallelität
    Bei der räumlichen Parallelität gibt es die arbeitenden Teile mehrfach, sie sind also physikalisch mehrfach vorhanden. Ein gutes Beispielt sind Multicore CPUs. Da kann auch pro Core eine Aufgabe ausgeführt werden, also mehrere parallel.
    Das Problem der räumlichen Parallelität ist, dass man nicht jede Aufgabe so aufteilen kann, dass sie parallel ausgeführt werden kann. Es kann zum Beispiel Probleme mit Abhängigkeiten geben, dass der nachfolgende Teil das Ergebnis des Vorgängers benötigt.
  • Zeitliche Parallelität (Pipelining)
    Um die zeitliche Parallelität zu verstehen, ist es sinnvoll sich mit den Zeitanforderungen an sequenzielle Schaltungen auseinanderzusetzen. Siehe dazu meinen Artikel zum Thema Timing und Glitches.

    Umso mehr Logik man in einem Takt durchlaufen will, umso mehr Zeit benötigt man (t_{pd}). Umso größer diese Zeit allerdings wird, umso kleiner wird die Taktfrequenz. Also teilt man die komplexe Logik in viele und simplere Logikblöcke auf, die nacheinander (nicht parallel!) durchlaufen werden. Da jeder dieser Blöcke das Ergebnis schnell bereit stellen kann, kann man die Taktfrequenz wieder hoch drehen. In Hardware wird dieses Verfahren auch als Pipelining bezeichnet, weil man die Logik verlegt und zwischen jeden Block ein Flipflop baut, dass das jeweilige Ergebnis bis zur nächsten Taktflanke zwischenspeichert.
    Das Problem beim Pipelining ist das man die Logikblöcke nur bis zu einem bestimmten Maß verkleinern kann. Außerdem steigt durch die zusätzlichen Flipflops die Latenz (also die Zeitspanne die benötigt wird, bis nach der Eingabe der Daten das Ergebnis bereit steht).
    Die zeitliche Parallelität kann man vergleichen mit dem Fließbandprinzip bei der Autofertigung. Um so mehr Arbeitsstationen man hat, und umso kürzer die Zeit ist, die pro Station benötigt wird, umso mehr Autos können auch produziert werden.

Durch die parallele Berechnung schafft man immer einen höheren Durchsatz (man kann also mehr Datensätze pro Zeiteinheit berechnen).

Sende Artikel als PDF an PDF Download

Timing und Glitches

17. Januar 2010

Jedes Bauelement benötigt einen Moment, bis es auf eine Änderung am Eingang reagiert. Natürlich sind diese Zeiten bei einzelnen Element sehr gering, aber wenn man richtige Schaltung baut, dann kann es sehr schnell zu Problemen kommen.

Schaltungen aus primitiven Elementen

Bei Schaltungen mit einfachen Bauteilen halten sich die Zeiten, die berücksichtigt werden müssen, in Grenzen. Es gibt nur 2: t_{cd} und t_{pd}. Mit t_{cd} (engl. contamination delay) gibt man die minimale Zeit an, bis die Schaltung den neuen Wert ausgibt. Mit t_{pd} (engl. propagation delay) dagegen die maximale Zeit, bis der neue Wert feststeht.
Zu beachten ist, dass es zwischen t_{cd} und t_{pd} zu mehreren Änderungen am Ausgang der Logik geben kann, auch wenn sich der Eingangswert nur ein einziges mal geändert hat. Das sind die sogenannten Glitches.

Glitches

In Logikschaltungen gibt es Pfade in denen nur wenige Elemente liegen (engl. short path), die das Ergebnis also sehr schnell berechen. Natürlich gibt es dann auch Pfade in denen viele (oder einfach mehr Elemente als in short path) liegen (engl. critical path), und deren Ergebnis erst später fertig ist. Deshalb kann es vorkommen, dass sich der Ausgang einer Logikschaltung zwischen t_{cd} und t_{pd} mehrmals ändert, bis er dann nach t_{pd} stabil das Ergebnis zeigt.
Beispiel in der Wikipedia.

Sequenzielle Logik

In sequentielle Logik sind sowohl Logikbausteine als auch Flip-Flops verbaut. Die Logikbausteine berechnen den neuen Wert, der dann am Eingang von einem Flip-Flop anliegt, das den Wert dann zur nächsten Taktflanke übernimmt. Daraufhin kann die Logik hinter einem Flip-Flop nach der Taktflanke eine neue Berechnung beginnen, da sich die Eingangswert eventuell geändert haben.
Da die Logik eine bestimme Zeit benötigt bis sie die Berechnung definitiv abgeschlossen hat, muss genügend Zeit zwischen zwei Taktflanken zur Verfügung stehen. Da man aber nicht 100%tig sagen kann wann das Flip-Flop den neuen Wert übernimmt und wann der neue Wert ausgegeben wird, brauchen wir auch einen Zeitpuffer für das Flip-Flop.
Genau gesagt, darf sich t_{setup} vor der Taktflanke bis t_{hold} nach der Taktflanke nichts mehr am Eingangssignal des Flip-Flops ändern. Nach dem das Flip-Flop den neuen Wert übernommen hat (man spricht auch von sampled), können wieder die Berechnungen durch die Logik stattfinden. Beide Zeiten werden als Abtastzeit bezeichnet, also das Zeitintervall um die Taktflanke herum in dem sich das Eingangssignal nicht ändern darf – es muss stabil sein. t_{a}=t_{setup}+t_{hold}

t_{a} ist also ein Zeitpuffer um die Taktflanke herum, falls ein Flip-Flop etwas früher oder etwas zu spät sampled.

Allerdings gibt es bei Flop-Flops noch weitere Verzögerungen die zu beachten sind: Ähnlich wie bei Logik kann es eine bestimme Zeit dauern, bis der neue Wert nach einer Taktflanke ausgegeben wird. Dazu gibt es zwei Zeiten: t_{ccq} (engl. contamination delay) gibt die minimal Zeit an, nach der der Ausgang bereits wieder aktuell sein könnte. Des weiteren sagt sie aus, wie lang nach einer Taktflanke definitiv keine Änderungen am Ausgang auftreten.
Schließlich gibt t_{pcq} (engl. propagation delay) die Zeit an, nach der der Ausgang in jedem Fall den korrekten Wert hat. Zwischen t_{ccq} und t_{pcq} könnte der Ausgang – genau wie bei Logikschaltungen – glitchen.

Taktfrequenz

Mit diesen Zeitanforderungen lässt sich bestimmen wie hoch der Takt maximal für eine Schaltung sein kann.
Wir müssen folgende Zeiten berücksichtigen:

  • t_{pcq}
    die Zeit die das Flip-Flop braucht, bis es nach einer Taktflanke den neuen Wert ausgibt
  • t_{pd}
    die Zeit die die Logik maximal braucht, bis sie den neuen Wert berechnet hat
  • t_{setup}
    die Zeit in der das Signal vor einer Taktflanke stabil sein muss

Die Zeit zwischen 2 Takten muss mindestens die Summe dieser drei Zeiten sein, also ist die Formel: T_c = t_{pcq} + t_{pd} + t_{setup}. Damit lässt sich dann auch die Taktfrequenz berechnen: f = \frac{1}{T_c}

Sende Artikel als PDF an PDF Download

Titanen des Erdreiches

10. Januar 2010

Ein toller Film über das Leben der Bagger! :D


Teil 1: http://www.youtube.com/watch?v=KNWXwHXZQBU


Teil 2: http://www.youtube.com/watch?v=qEsXJgmIUX0

Sende Artikel als PDF an PDF Creator

Drupal Internationalisierung (i18n)

6. Januar 2010

Eine gute Anleitung welche Module man benötigt und was man tun muss, um Drupal zu internationalisieren, findet man hier: http://drupal-translation.com/de/node/11.

Sende Artikel als PDF an PDF Download

apt-get Downloadspeed begrenzen

28. Dezember 2009

Geht ganz einfach indem man beim Aufruf von apt-get folgendes angibt

apt-get -o Acquire::http::Dl-Limit=25 ...

Will man den Speed dauerhaft, also bei jedem Aufruf von apt-get begrenzen, empfiehlt es sich, die Datei /etc/apt/apt.conf.d/76download zu erstellen mit folgendem Inhalt:

Acquire
{
Queue-mode "access";
http
{
Dl-Limit "25";
};
};
Sende Artikel als PDF an PDF Drucker

Binomialkoeffizient

23. Dezember 2009

Mit dem Binomialkoeffizient kann man die Anzahl der Möglichkeiten berechnen, wie man k-Elemente aus einer n-elementigen Menge anordnen kann. Dabei gibt es keine Wiederholungen und die Reihenfolge spielt auch keine Rolle.
Das Symbol ist: n \choose k (gesprochen “n über k”).

Die Formel zur Berechnung ist: \binom nk = \frac{n!}{k!(n-k)!}

Bedeutung der einzelnen Elemente

Man stellt sich dabei am besten vor, dass man die n-Elemente beliebig anordnet und dann die ersten k-Elemente zieht (sich also nur die ersten k-Elemente ansieht). Der Rest wird ignoriert. Deshalb steht im Zähler {n!} – also die Anzahl der Möglichkeiten n-Elemente anzuordnen wenn die Reihenfolge wichtig ist.

Da die Reihenfolge beim Binomialkoeffizient aber keine Rolle spielen soll, steht im Nenner {k!} multipliziert mit den restlichen Elementen die unwichtig sind, also {(n - k)!}.

Sende Artikel als PDF an PDF

Ubuntu: Eclipse Buttons nicht klickbar

4. Dezember 2009

Ich habe heute versucht auf meinem Ubuntu 9.04 mit einem frischem Eclipse ein Projekt mittels CVS in meinen workspace zu laden. Leider war es nicht möglich auf den next Button im CVS Dialog zu klicken. Auch der back Button war “kaputt”, der cancel Button funktionierte aber dummerweise!

Wenn man, bevor man Eclipse startet, folgende Umgebungsvariable setzt funktioniert es wieder:

export GDK_NATIVE_WINDOWS=true
Sende Artikel als PDF an PDF Creator

TikiWiki: eMail Bestätigung deaktivieren

2. Dezember 2009

Leider gibt es auch Probleme wenn man als admin einen neuen Benutzer anlegt. Auch diese Benutzer sollen ihre eMail Adresse aktivieren.

Die gesuchte Einstellung ist leider sehr gut versteckt. Man findet sie, wenn man als admin eingeloggt ist, unter
Admin Home -> Anmeldung
Wenn man auf dieser Seite die Option Benutzer können sich registrieren. aktiviert und speichert werden neue Einstellmöglichkeiten direkt unter Benutzer können sich registrieren. aufgeführt.
Darunter auch die Gesuchte Validate by email. die aktiviert ist. Wenn man sie deaktiviert kann man sich mit einem neu erstellen Benutzer einloggen, ohne das die eMail Adresse bestätigt wurde.

Auch nach dem man die Option, dass sich Benutzer selbst registrieren können, wieder deaktiviert hat, ist die Einstellung geblieben, dass neue Benutzer ihr eMail Adresse nicht bestätigen müssen. Ab jetzt kann nur noch der admin Benutzer erstellen, die sich ohne Aktivierung einloggen können.

Sende Artikel als PDF an PDF Drucker