Tracks
/
x86-64 Assembly
x86-64 Assembly
/
Übungen
/
Freelancer-Sätze
Freelancer-Sätze

Freelancer-Sätze

Lernübung

Einführung

Gleitkommazahlen

Eine Gleitkommazahl ist eine Zahl mit einem Nachkommateil, wie zum Beispiel -1.23 oder 3.1415.

Um eine solche Zahl als Bytefolge darzustellen, verwendet x86-64 den IEEE-754-Standard. Die beiden häufigsten Formate in diesem Standard sind Gleitkommazahlen mit einfacher Genauigkeit und mit doppelter Genauigkeit. x86-64 unterstützt beide.

Eine Gleitkommazahl mit einfacher Genauigkeit ist 32 Bit breit, eine mit doppelter Genauigkeit 64 Bit.

XMM-Register

In x86-64 gibt es 16 dedizierte Register für Gleitkommaarithmetik, benannt von xmm0 bis xmm15.

Diese Register sind mindestens 128 Bit breit, doch neuere Prozessoren erweitern dies auf 256 Bit oder 512 Bit. In der Praxis nutzen die meisten Gleitkommazahlen jedoch nur die untersten 32 Bit oder 64 Bit, je nach gewünschter Genauigkeit.

Umwandlung zwischen Zahlen

Es gibt eine Familie von Instruktionen, um zwischen Zahlenformaten umzuwandeln: cvtxx2yy.

Sowohl xx als auch yy sind keine Literale, sondern Platzhalter:

  • xx ist ein Platzhalter für den Typ des Quelloperanden.
  • yy ist ein Platzhalter für den Typ des Zieloperanden.

Dieser Platzhalter kann viele Formen annehmen, darunter:

Platzhalter Bedeutung
si vorzeichenbehaftete Ganzzahl
ss 32-Bit-Gleitkommazahl
sd 64-Bit-Gleitkommazahl

Zum Beispiel:

cvtsi2ss xmm0, eax ; converts a 32-bit signed integer to a single-precision floating-point
cvtsd2si rax, xmm1 ; converts a double-precision floating-point to a 64-bit signed integer

Beachte, dass es möglich ist, eine 32-Bit-Ganzzahl in eine 64-Bit-Gleitkommazahl oder eine 64-Bit-Ganzzahl in eine 32-Bit-Gleitkommazahl umzuwandeln. Ebenso ist es möglich, eine 32-Bit-Gleitkommazahl in eine 64-Bit-Ganzzahl oder eine 64-Bit-Gleitkommazahl in eine 32-Bit-Ganzzahl umzuwandeln. Mit anderen Worten: Die Größe beider Operanden in einem cvtxx2yy muss nicht gleich sein:

cvtsi2sd xmm0, eax ; converts a 32-bit signed integer to a double-precision floating-point
cvtsi2ss xmm0, rax ; converts a 64-bit signed integer to a single-precision floating-point
cvtss2si rax, xmm0 ; converts a single-precision floating-point to a 64-bit signed integer
cvtsd2si eax, xmm0 ; converts a double-precision floating-point to a 32-bit signed integer

Wenn die Gleitkommazahl nicht exakt als Ganzzahl ausgedrückt werden kann, rundet cvtxx2si die Zahl entsprechend der Rundungssteuerung in einem speziellen Register namens mxcsr. Das kann ein Runden auf den nächsten Wert, ein Abrunden, ein Aufrunden oder ein Abschneiden sein. Beim Funktionsaufruf gibt es keinen garantierten Standardwert.

Beachte, dass ein exaktes Ergebnis nicht gerundet wird und daher von der Rundungssteuerung nicht betroffen ist. Zum Beispiel würde 42.0 immer in 42 umgewandelt.

Es gibt eine ähnliche Instruktionsfamilie mit dem Format cvttxx2si (mit einem zusätzlichen t), die das Ergebnis immer abschneidet.

Runden

Die Instruktionsfamilie roundxx wandelt eine Gleitkommazahl im Quelloperanden in eine gerundete Gleitkommazahl um, die im Zieloperanden gespeichert wird.

Hier ist xx wie üblich ein Platzhalter für den Typ der Operanden: ss für Gleitkommazahlen mit einfacher Genauigkeit und sd für solche mit doppelter Genauigkeit.

Diese Instruktionen nehmen eine konstante Zahl als dritten Operanden. Diese Zahl gibt den Rundungsmodus an:

Zahl Modus
0 Nächster Wert
1 Abrunden (nach unten)
2 Aufrunden (nach oben)
3 Abschneiden

Zum Beispiel:

roundss xmm0, xmm1, 1 ; this rounds down (takes the floor) a 32-bit floating-point in xmm1 and stores it in xmm0
roundsd xmm2, xmm2, 2 ; this rounds up (takes the ceil) a 64-bit floating-point in xmm2 and stores it in xmm2

Da diese Instruktionen ein exaktes Ergebnis liefern, können sie zur Vorbereitung auf ein cvtxx2si verwendet werden.

Arithmetische Instruktionen

Viele Operationen mit Gleitkommazahlen verwenden Instruktionen mit einem ähnlichen Namen wie ihr Gegenstück für Ganzzahlen, ergänzt um den nötigen Platzhalter (ss oder sd) am Ende. Diese Instruktionen haben zwei Operanden, mit der üblichen Semantik, auch die, die eine Multiplikation oder Division durchführen:

addss xmm1, xmm2 ; xmm1 = xmm1 + xmm2 (all 32-bit floating-point)
mulsd xmm4, xmm5 ; xmm4 = xmm4 * xmm5 (all 64-bit floating-point)
divss xmm0, xmm3 ; xmm0 = xmm0 / xmm3 (all 32-bit floating-point)

Verschieben

Die Instruktionen, um von einem XMM-Register in ein anderes zu verschieben, sind movss oder movsd:

movss xmm1, xmm0 ; this copies a 32-bit floating-point from xmm0 to xmm1
movsd xmm6, xmm4 ; this copies a 64-bit floating-point from xmm4 to xmm6

Es ist nicht möglich, einen Immediate-Wert (eine konstante vorzeichenbehaftete Ganzzahl) direkt in ein xmm-Register zu verschieben. Diese Zahl muss zuerst in ein Allzweckregister verschoben und dann mit cvtsi2xx umgewandelt werden:

mov rax, 10        ; rax is a 64-bit integer with value 10
cvtsi2sd xmm0, rax ; xmm0 is a 64-bit floating-point with value 10.0

Vergleiche

Es gibt zwei Gruppen von Instruktionen, um zwei Gleitkommazahlen zu vergleichen. Sie haben die Form comixx und ucomixx, wobei xx entweder ss oder sd ist. Beide setzen wie üblich Flags in rflags, mit derselben Semantik wie cmp.

Der Unterschied zwischen ihnen besteht darin, dass ucomixx das parity flag (PF) setzt, wenn eine der beiden Gleitkommazahlen den Wert NaN hat, während comixx in diesem Fall eine Ausnahme auslöst.

Der Vergleich zwischen Gleitkommawerten ist vorzeichenlos:

ucomisd xmm0, xmm1
ja .greater         ; 'ja' must be used for "greater", not 'jg'
jb .lesser          ; 'jb' must be used for "lesser", not 'jl'

Aufrufkonvention

In der System-V-ABI werden die ersten acht Gleitkomma-Argumente der Reihe nach in xmm0 bis xmm7 an Funktionen übergeben. Gleitkommawerte werden in xmm0 und, falls nötig, in xmm1 von Funktionen zurückgegeben.

Alle xmm-Register stehen frei zur Verfügung, keines von ihnen ist für den Aufrufer reserviert.

Speicher

Gleitkommawerte können im Speicher mit derselben Semantik wie Ganzzahlen derselben Größe definiert werden. NASM (The Netwide Assembler, der in diesem Track verwendete Assembler) erlaubt auch die Deklaration von Gleitkommawerten in wissenschaftlicher Notation.

section .data
    pi dq 3.141592653589793 ; this is a double-precision floating-point value
    exp_num dd 1.e5 ; this is a single precision floating-point value equal to 1 * 10⁵
    exp_num2 dd 1.e+5 ; this is a single precision floating-point value equal to 1 * 10⁵
    frac dq 1.e-10 ; this is a double precision floating-point value equal to 1 * 10⁻¹⁰, i.e., 0.0000000001

Anleitung

In dieser Übung schreibst du Code, der einem Freelancer bei der Kommunikation mit einem Projektmanager hilft. Deine Aufgabe ist es, ein paar Hilfsfunktionen bereitzustellen, mit denen du schnell Tages- und Monatssätze berechnen kannst, optional mit einem gegebenen Rabatt.

Zuerst legen wir ein paar Regeln zwischen dem Freelancer und dem Projektmanager fest:

  • Der Tagessatz ist das 8-Fache des Stundensatzes.
  • Ein Monat hat 22 abrechenbare Tage.

Manchmal bietet der Freelancer an, einen Rabatt auf seinen Tagessatz zu gewähren (zum Beispiel für seine treuesten Kunden oder gemeinnützige Kunden).

Rabatte werden als Bruchzahlen modelliert, die Prozentwerte darstellen, zum Beispiel 25.0 (25 %).

Note

Das sind die Suffixe für Gleitkomma-Befehle:

Suffix Operandengröße
ss 32 Bit
sd 64 Bit

Das sind einige der Befehle, die in diesem Konzept erwähnt werden:

Befehl Beschreibung
movss/movsd a, b kopiert b nach a
addss/addsd a, b a = a + b
subss/subsd a, b a = a - b
mulss/mulsd a, b a = a * b
divss/divsd a, b a = a / b
cvtsi2ss/cvtsi2sd a, b wandelt die Ganzzahl b in die Gleitkommazahl a um
roundss/roundsd a, b, c rundet die Gleitkommazahl b gemäß c und speichert das Ergebnis in a
cvtss2si/cvtsd2si a, b wandelt die Gleitkommazahl b in die Ganzzahl a um
comiss/comisd a, b vergleicht a und b, löst eine Ausnahme aus, wenn NaN
ucomiss/ucomisd a, b vergleicht a und b, setzt PF, wenn NaN

Das sind die Rundungssteuerzahlen in roundss und roundsd:

Zahl Modus
0 Nächster Wert
1 Abrunden (nach unten)
2 Aufrunden (nach oben)
3 Abschneiden

1. Tagessatz anhand eines Stundensatzes berechnen

Implementiere eine Funktion namens daily_rate, die den Tagessatz anhand eines als Parameter übergebenen Stundensatzes berechnet, einer 64-Bit-Gleitkommazahl. Der Vertrag legt fest, dass ein Tag 8 abrechenbare Stunden hat.

daily_rate(60)
// => 480.0

Der zurückgegebene Tagessatz sollte eine 64-Bit-Gleitkommazahl sein.

2. Einen rabattierten Preis berechnen

Implementiere eine Funktion apply_discount, die den Preis nach einem Rabatt berechnet. Sie sollte zwei Parameter akzeptieren: den ursprünglichen Preis und den Rabattsatz in Prozent, beide als 64-Bit-Gleitkommazahl.

apply_discount(150.0, 10.0)
// => 135.0

Der zurückgegebene Wert sollte immer eine 64-Bit-Gleitkommazahl sein.

3. Monatssatz anhand eines Stundensatzes und eines Rabatts berechnen

Implementiere eine Funktion monthly_rate, die den rabattierten Monatssatz berechnet. Sie nimmt zwei Parameter, einen Stundensatz und den Rabatt in Prozent, beide als 64-Bit-Gleitkommazahl.

monthly_rate(77.0, 10.5)
// => 12130

Der zurückgegebene Monatssatz sollte auf die nächste 64-Bit-Ganzzahl aufgerundet werden (nimm also die Obergrenze).

4. Die Anzahl der vollständigen Arbeitstage anhand eines Budgets, eines Stundensatzes und eines Rabatts berechnen

Implementiere eine Funktion days_in_budget, die folgende Parameter nimmt:

  1. Ein Budget als 64-Bit-Ganzzahl ohne Vorzeichen.
  2. Einen Stundensatz als 64-Bit-Gleitkommazahl.
  3. Einen Rabatt in Prozent als 64-Bit-Gleitkommazahl.

Diese Funktion sollte die Anzahl der vollständigen Arbeitstage zurückgeben, die das Budget abdeckt.

days_in_budget(20000, 80, 11.0)
// => 35

Die zurückgegebene Anzahl von Tagen sollte auf die nächste 32-Bit-Ganzzahl abgerundet werden (nimm also die Untergrenze).

Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
x86-64 Assembly Exercism

Bereit, mit Freelancer-Sätze zu starten?

Melde dich bei Exercism an, um x86-64 Assembly mit 22 Konzepte130 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.