From 641b7fd2dec17ea5e7a1103da0bc6ac7079c9053 Mon Sep 17 00:00:00 2001 From: Dan Novischi Date: Tue, 19 May 2026 11:55:25 +0300 Subject: [PATCH] Reorganize floating-point demos into separate directories - Move each demo into its own subdirectory (arrayfsum, quad, fpadd, fpprint, fp_representation, arrayfsum_inline) - Create individual Makefiles for each demo - Update README.md to document new directory structure - Create master Makefile in root to build all demos - Fix DOS line endings in all source files - Fix code style issues per checkpatch - Add .gitignore to exclude build artifacts and .vscode/ Signed-off-by: Dan Novischi --- curs/chap-11-floating-point/.gitignore | 10 + .../01-all-demos/.gitignore | 8 - .../01-all-demos/Makefile | 52 ---- .../01-all-demos/README.md | 0 .../01-all-demos/arrayfsum_inline.c | 14 -- .../01-all-demos/arrayfsuma.asm | 20 -- .../01-all-demos/arrayfsumc.c | 23 -- .../01-all-demos/fpadd.asm | 29 --- .../01-all-demos/fpprint.c | 79 ------ .../01-all-demos/quada.asm | 53 ----- .../01-all-demos/quadc.c | 23 -- curs/chap-11-floating-point/README.md | 225 ++++++++++++++++++ .../chap-11-floating-point/arrayfsum/Makefile | 23 ++ .../arrayfsum/arrayfsuma.asm | 30 +++ .../arrayfsum/arrayfsuma.h | 8 + .../arrayfsum/arrayfsumc.c | 26 ++ .../arrayfsum_inline/Makefile | 14 ++ .../arrayfsum_inline/arrayfsum_inline.c | 22 ++ .../fp_representation/Makefile | 20 ++ .../fp_representation.c | 7 +- curs/chap-11-floating-point/quad/Makefile | 23 ++ curs/chap-11-floating-point/quad/quada.asm | 71 ++++++ curs/chap-11-floating-point/quad/quada.h | 9 + curs/chap-11-floating-point/quad/quadc.c | 26 ++ 24 files changed, 513 insertions(+), 302 deletions(-) create mode 100644 curs/chap-11-floating-point/.gitignore delete mode 100644 curs/chap-11-floating-point/01-all-demos/.gitignore delete mode 100644 curs/chap-11-floating-point/01-all-demos/Makefile delete mode 100644 curs/chap-11-floating-point/01-all-demos/README.md delete mode 100644 curs/chap-11-floating-point/01-all-demos/arrayfsum_inline.c delete mode 100644 curs/chap-11-floating-point/01-all-demos/arrayfsuma.asm delete mode 100644 curs/chap-11-floating-point/01-all-demos/arrayfsumc.c delete mode 100644 curs/chap-11-floating-point/01-all-demos/fpadd.asm delete mode 100644 curs/chap-11-floating-point/01-all-demos/fpprint.c delete mode 100644 curs/chap-11-floating-point/01-all-demos/quada.asm delete mode 100644 curs/chap-11-floating-point/01-all-demos/quadc.c create mode 100644 curs/chap-11-floating-point/README.md create mode 100644 curs/chap-11-floating-point/arrayfsum/Makefile create mode 100644 curs/chap-11-floating-point/arrayfsum/arrayfsuma.asm create mode 100644 curs/chap-11-floating-point/arrayfsum/arrayfsuma.h create mode 100644 curs/chap-11-floating-point/arrayfsum/arrayfsumc.c create mode 100644 curs/chap-11-floating-point/arrayfsum_inline/Makefile create mode 100644 curs/chap-11-floating-point/arrayfsum_inline/arrayfsum_inline.c create mode 100644 curs/chap-11-floating-point/fp_representation/Makefile rename curs/chap-11-floating-point/{01-all-demos => fp_representation}/fp_representation.c (76%) create mode 100644 curs/chap-11-floating-point/quad/Makefile create mode 100644 curs/chap-11-floating-point/quad/quada.asm create mode 100644 curs/chap-11-floating-point/quad/quada.h create mode 100644 curs/chap-11-floating-point/quad/quadc.c diff --git a/curs/chap-11-floating-point/.gitignore b/curs/chap-11-floating-point/.gitignore new file mode 100644 index 00000000..69446b02 --- /dev/null +++ b/curs/chap-11-floating-point/.gitignore @@ -0,0 +1,10 @@ +.vscode/ +*.o +*.s +fpadd +fpprint +fp-m64 +fp-m64-O2 +quadc +arrayfsumc +arrayfsum_inline.o diff --git a/curs/chap-11-floating-point/01-all-demos/.gitignore b/curs/chap-11-floating-point/01-all-demos/.gitignore deleted file mode 100644 index 0519fa53..00000000 --- a/curs/chap-11-floating-point/01-all-demos/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/fp-m32 -/fp-m32-O2 -/fp-m32.s -/fp-m32-O2.s -/arrayfsumc -/quadc -/fpadd -/fpprint diff --git a/curs/chap-11-floating-point/01-all-demos/Makefile b/curs/chap-11-floating-point/01-all-demos/Makefile deleted file mode 100644 index dd921f9f..00000000 --- a/curs/chap-11-floating-point/01-all-demos/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -AFILES = arrayfsuma.asm quada.asm fpadd.asm -CFILES = arrayfsumc.c arrayfsum_inline.c quadc.c fpprint.c - -OBJS = $(AFILES:.asm=.o) -NASM = nasm -ASM_FLAGS = -f elf32 -g -F dwarf -LD = cc -m32 -g -BINARIES = arrayfsumc quadc fp-m32 fp-m32-O2 fpadd fpprint fp-m64 fp-m64-O2 - -all : $(BINARIES) - -arrayfsumc: arrayfsumc.o arrayfsuma.o - $(LD) -o $@ $^ - -quadc: quadc.o quada.o - $(LD) -o $@ $^ - -fpadd: fpadd.o - $(LD) -o $@ $^ - -fpprint: fpprint.o - $(LD) -o $@ $^ - -fp-m32-O2: fp_representation.c - $(CC) -m32 -O2 -o $@ $^ - $(CC) -m32 -O2 -S -masm=intel -o fp-m32-O2.s $< - -fp-m32: fp_representation.c - $(CC) -m32 -o $@ $^ - $(CC) -m32 -S -masm=intel -o fp-m32.s $< - -fp-m64-O2: fp_representation.c - $(CC) -m64 -O2 -o $@ $^ - $(CC) -m64 -O2 -S -masm=intel -o fp-m64-O2.s $< - -fp-m64: fp_representation.c - $(CC) -m64 -o $@ $^ - $(CC) -m64 -S -masm=intel -o fp-m64.s $< - - - -%.o : %.c -# $(warning NASM=$(NASM) FLAGS=$(ASM_FLAGS)) - cc -m32 -g -c -o $@ $< - -%.o : %.asm -# $(warning NASM=$(NASM) FLAGS=$(ASM_FLAGS)) - $(NASM) $(ASM_FLAGS) -o $@ $< - -clean: - rm -f *.o $(BINARIES) *.s - rm -f *~ diff --git a/curs/chap-11-floating-point/01-all-demos/README.md b/curs/chap-11-floating-point/01-all-demos/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/curs/chap-11-floating-point/01-all-demos/arrayfsum_inline.c b/curs/chap-11-floating-point/01-all-demos/arrayfsum_inline.c deleted file mode 100644 index 7c737012..00000000 --- a/curs/chap-11-floating-point/01-all-demos/arrayfsum_inline.c +++ /dev/null @@ -1,14 +0,0 @@ -double array_fsum(double* value, int size) -{ - double sum; - asm(" fldz; " /* sum = 0 */ - "add_loop: jecxz done; " - " decl %%ecx; " - " faddl (%%ebx,%%ecx,8);" - " jmp add_loop; " - "done: " - :"=t"(sum) /* output */ - :"b"(value),"c"(size) /* inputs */ - :"cc"); /* clobber list */ - return(sum); -} diff --git a/curs/chap-11-floating-point/01-all-demos/arrayfsuma.asm b/curs/chap-11-floating-point/01-all-demos/arrayfsuma.asm deleted file mode 100644 index 8fd3e8bc..00000000 --- a/curs/chap-11-floating-point/01-all-demos/arrayfsuma.asm +++ /dev/null @@ -1,20 +0,0 @@ -;------------------------------------------------------------- -; This procedure receives an array pointer and its size via -; the stack. It computes the array sum and returns it via ST0. -;------------------------------------------------------------- -segment .text -global array_fsum - -array_fsum: - enter 0,0 - mov EDX,[EBP+8] ; copy array pointer to EDX - mov ECX,[EBP+12] ; copy array size to ECX - fldz ; ST0 = 0 (ST0 keeps the sum) -add_loop: - jecxz done - dec ECX ; update array index - fadd qword[EDX+ECX*8] ; ST0 = ST0 + arrary_element - jmp add_loop -done: - leave - ret \ No newline at end of file diff --git a/curs/chap-11-floating-point/01-all-demos/arrayfsumc.c b/curs/chap-11-floating-point/01-all-demos/arrayfsumc.c deleted file mode 100644 index 40f44c6f..00000000 --- a/curs/chap-11-floating-point/01-all-demos/arrayfsumc.c +++ /dev/null @@ -1,23 +0,0 @@ -/************************************************************ - * This program reads SIZE values into an array and calls - * an assembly language program to compute the array sum. - * The assembly program is in the file "arrayfsuma.asm". - ************************************************************/ -#include - -#define SIZE 10 - -int main(void) -{ - double value[SIZE]; - int i; - extern double array_fsum(double*, int); - - printf("Input %d array values:\n", SIZE); - for (i = 0; i < SIZE; i++) - scanf("%lf",&value[i]); - - printf("Array sum = %lf\n", array_fsum(value,SIZE)); - - return 0; -} diff --git a/curs/chap-11-floating-point/01-all-demos/fpadd.asm b/curs/chap-11-floating-point/01-all-demos/fpadd.asm deleted file mode 100644 index a07d4d6e..00000000 --- a/curs/chap-11-floating-point/01-all-demos/fpadd.asm +++ /dev/null @@ -1,29 +0,0 @@ -section .rodata - fmt db "result: %f", 10, 0 - -section .data - result dq 0 - -section .text - -extern printf -global main - -main: - push ebp - mov ebp, esp - - sub esp, 4 - mov dword [esp], 0x40000000 - fld dword [esp] - fadd dword [esp] - fstp qword [result] - - push dword [result+4] - push dword [result] - push fmt - call printf - add esp, 8 - - leave - ret diff --git a/curs/chap-11-floating-point/01-all-demos/fpprint.c b/curs/chap-11-floating-point/01-all-demos/fpprint.c deleted file mode 100644 index ca355feb..00000000 --- a/curs/chap-11-floating-point/01-all-demos/fpprint.c +++ /dev/null @@ -1,79 +0,0 @@ -#include - -static void print_bits(unsigned int m, unsigned int len) -{ - size_t i; - - for (i = len; i > 0; i--) - printf("%u", (m & (1 << (i-1))) >> (i-1)); -} - -static void print_long_bits(unsigned long long m, unsigned int len) -{ - size_t i; - - for (i = len; i > 0; i--) - printf("%llu", (m & (1ULL << (i-1))) >> (i-1)); -} - -static void print_float(float f) -{ - unsigned int s, e, m; - unsigned int equiv = * ((unsigned int *) &f); - - s = equiv >> 31; - e = (equiv & 0x7fffffff) >> 23; - m = (equiv & 0x007fffff); - - printf("f: %f (0x%08x)\n", f, equiv); - printf("s: %u, e: %u, m: %u (0x%08x) (", s, e, m, m); - print_bits(m, 23); - printf(")\n"); -} - -static void print_double(double d) -{ - unsigned long long s, e, m; - unsigned long long equiv = * ((unsigned long long *) &d); - - s = equiv >> 63; - e = (equiv & 0x7fffffffffffffffULL) >> 52; - m = (equiv & 0x000fffffffffffffULL); - - printf("f: %lf (0x%016llx)\n", d, equiv); - printf("s: %llu, e: %llu, m: %llu (0x%016llx) (", s, e, m, m); - print_long_bits(m, 52); - printf(")\n"); -} - -int main(void) -{ - print_float(2); - print_float(4); - print_float(0.5); - print_float(0.125); - print_float(6.125); - print_float(4608); - print_float(1.0/0.0); - print_float(-10000.0/0.0); - print_float(0.0/0.0); - - print_double(2); - print_double(4); - print_double(0.5); - print_double(0.125); - print_double(6.125); - print_double(4608); - print_double(1.0/0.0); - print_double(-10000.0/0.0); - print_double(0.0/0.0); - - { - long double ld = 2; - - printf("ld: %Lf\n", ld); - printf("sizeof(ld): %d\n", sizeof(ld)); - } - - return 0; -} diff --git a/curs/chap-11-floating-point/01-all-demos/quada.asm b/curs/chap-11-floating-point/01-all-demos/quada.asm deleted file mode 100644 index 04206113..00000000 --- a/curs/chap-11-floating-point/01-all-demos/quada.asm +++ /dev/null @@ -1,53 +0,0 @@ -;------------------------------------------------------------- -; This procedure receives three constants a, b, c and -; pointers to two roots via the stack. It computes the two -; real roots if they exist and returns them in root1 & root2. -; In this case, EAX = 1. If no real roots exist, EAX = 0. -;------------------------------------------------------------- -%define a qword[EBP+8] -%define b qword[EBP+16] -%define c qword[EBP+24] -%define root1 dword[EBP+32] -%define root2 dword[EBP+36] - -segment .text -global quad_roots - -quad_roots: - enter 0,0 - fld a ; a - fadd ST0 ; 2a - fld a ; a,2a - fld c ; c,a,2a - fmulp ST1 ; ac,2a - fadd ST0 ; 2ac,2a - fadd ST0 ; 4ac,2a - fchs ; -4ac,2a - fld b ; b,-4ac,2a - fld b ; b,b,-4ac,2a - fmulp ST1 ; b*b,-4ac,2a - faddp ST1 ; b*b-4ac,2a - ftst ; compare (b*b-4ac) with 0 - fstsw AX ; store status word in AX - sahf - jb no_real_roots - fsqrt ; sqrt(b*b-4ac),2a - fld b ; b,sqrt(b*b-4ac),2a - fchs ; -b,sqrt(b*b-4ac),2a - fadd ST1 ; -b+sqrt(b*b-4ac),sqrt(b*b-4ac),2a - fdiv ST2 ; -b+sqrt(b*b-4ac)/2a,sqrt(b*b-4ac),2a - mov EAX,root1 - fstp qword[EAX] ; store root1 - fchs ; -sqrt(b*b-4ac),2a - fld b ; b,sqrt(b*b-4ac),2a - fsubp ST1 ; -b-sqrt(b*b-4ac),2a - fdivrp ST1 ; -b-sqrt(b*b-4ac)/2a - mov EAX,root2 - fstp qword[EAX] ; store root2 - mov EAX,1 ; real roots exist - jmp short done -no_real_roots: - sub EAX,EAX ; EAX = 0 (no real roots) -done: - leave - ret \ No newline at end of file diff --git a/curs/chap-11-floating-point/01-all-demos/quadc.c b/curs/chap-11-floating-point/01-all-demos/quadc.c deleted file mode 100644 index a7e35dc0..00000000 --- a/curs/chap-11-floating-point/01-all-demos/quadc.c +++ /dev/null @@ -1,23 +0,0 @@ -/************************************************************ - * This program reads three constants (a, b, c) and calls an - * assembly language program to compute the roots of the - * quadratic equation. - * The assembly program is in the file "quada.asm". - ************************************************************/ -#include - -int main(void) -{ - double a, b, c, root1, root2; - extern int quad_roots(double, double, double, double*, double*); - - printf("Enter quad constants a, b, c: "); - scanf("%lf %lf %lf",&a, &b, &c); - - if (quad_roots(a, b, c, &root1, &root2)) - printf("Root1 = %lf and root2 = %lf\n", root1, root2); - else - printf("There are no real roots.\n"); - - return 0; -} diff --git a/curs/chap-11-floating-point/README.md b/curs/chap-11-floating-point/README.md new file mode 100644 index 00000000..e74ee25f --- /dev/null +++ b/curs/chap-11-floating-point/README.md @@ -0,0 +1,225 @@ +# Chapter 11: Floating-Point Demos (x86-64) + +This directory contains standalone demos for floating-point representation and floating-point computation in x86-64. +All assembly examples use NASM with ELF64 output and follow the System V AMD64 ABI. + +--- + +## Directory Structure + +Each demo is organized in its own subdirectory with individual Makefiles: + +* `arrayfsum/` - Array summation with x64 assembly implementation +* `quad/` - Quadratic equation solver with real roots in x64 assembly +* `fpadd/` - Floating-point addition demo and printf in assembly +* `fpprint/` - Utility to inspect IEEE-754 bit fields for `float` and `double` +* `fp_representation/` - C demo of floating-point precision, associativity, and rounding artifacts +* `arrayfsum_inline/` - Inline assembly variant for array summation + +--- + +## Build + +To build a specific demo, enter its directory and run make: + +```console +cd arrayfsum +make +``` + +To clean artifacts from a specific demo: + +```console +cd arrayfsum +make clean +``` + +To build all demos at once, you can use a loop: + +```console +for dir in arrayfsum quad fpadd fpprint fp_representation arrayfsum_inline; do + make -C $dir +done +``` + +--- + +## Demos + +### Demo: `arrayfsum` - Array Sum with Assembly + +**Location:** `arrayfsum/` + +**Files:** `arrayfsuma.asm`, `arrayfsumc.c` + +The program reads 10 `double` values, calls `array_fsum`, and prints the total sum. + +`array_fsum` follows the x64 calling convention: + +* `rdi`: pointer to array +* `esi`: number of elements +* `xmm0`: return value (`double` sum) + +The implementation iterates over the array and accumulates with `addsd`. + +**Build and Run:** + +```console +cd arrayfsum +make +./arrayfsumc +``` + +--- + +### Demo: `quad` - Quadratic Roots in Assembly + +**Location:** `quad/` + +**Files:** `quada.asm`, `quadc.c` + +`quadc` reads coefficients `a`, `b`, `c` and calls: + +```c +int quad_roots(double a, double b, double c, double *root1, double *root2); +``` + +The assembly function computes the discriminant: + +$$ +\Delta = b^2 - 4ac +$$ + +If $\Delta < 0$, it returns `0` (no real roots). +Otherwise, it computes and stores: + +$$ +\text{root1} = \frac{-b + \sqrt{\Delta}}{2a} +$$ + +$$ +\text{root2} = \frac{-b - \sqrt{\Delta}}{2a} +$$ + +**Build and Run:** + +```console +cd quad +make +./quadc +``` + +--- + +### Demo: `fpadd` - Floating-Point Addition + +**Location:** `fpadd/` + +**File:** `fpadd.asm` + +Pure x64 assembly demo of floating-point addition and `printf` output. +Demonstrates SSE/SSE2 floating-point operations and calling conventions for `printf`. + +This demo computes `2.0 + 2.0` using SSE2 (`movsd`/`addsd`) and prints the result with `printf`. +Because `printf` is variadic, the call sets `eax = 1` to indicate one vector argument (`xmm0`) is used. + +**Build and Run:** + +```console +cd fpadd +make +./fpadd +``` + +Expected output: + +```text +result: 4.000000 +``` + +--- + +### Demo: `fpprint` - IEEE-754 Bit Field Inspector + +**Location:** `fpprint/` + +**File:** `fpprint.c` + +Utility to inspect IEEE-754 bit fields for `float` and `double` values. +Prints sign, exponent, and mantissa components. + +This utility prints sign/exponent/mantissa fields for several `float` and `double` values, including infinities and NaN. +It is useful for visualizing binary representation details. + +**Build and Run:** + +```console +cd fpprint +make +./fpprint +``` + +--- + +### Demo: `fp_representation` - Floating-Point Precision + +**Location:** `fp_representation/` + +**File:** `fp_representation.c` + +C demo illustrating floating-point precision, associativity issues, and rounding artifacts. +Compiled at two optimization levels: + +* `fp-m64`: Compiled with `-m64` (no optimization) +* `fp-m64-O2`: Compiled with `-m64 -O2` (optimized) + +Also generates Intel syntax assembly files: + +* `fp-m64.s`: Assembly without optimization +* `fp-m64-O2.s`: Assembly with optimization + +This program illustrates: + +* decimal-to-binary approximation errors (e.g. `0.1`) +* non-associativity in floating-point arithmetic +* precision loss at large magnitudes + +**Build and Run:** + +```console +cd fp_representation +make +./fp-m64 +./fp-m64-O2 +``` + +--- + +### Demo: `arrayfsum_inline` - Inline Assembly Summation + +**Location:** `arrayfsum_inline/` + +**File:** `arrayfsum_inline.c` + +Inline-assembly variant of array summation using x87 instructions from C. +Demonstrates how to pass C values into fixed registers and return a floating-point result +through inline-asm constraints. + +This file is compiled to an object file (no standalone binary). + +**Build:** + +```console +cd arrayfsum_inline +make +``` + +--- + +## Notes + +* All binaries are built in their respective directories +* Each demo has its own Makefile for independent building +* To clean artifacts, run `make clean` in each demo directory +* Assembly files use Intel syntax with NASM +* All code follows the System V AMD64 ABI calling convention diff --git a/curs/chap-11-floating-point/arrayfsum/Makefile b/curs/chap-11-floating-point/arrayfsum/Makefile new file mode 100644 index 00000000..682d833f --- /dev/null +++ b/curs/chap-11-floating-point/arrayfsum/Makefile @@ -0,0 +1,23 @@ +NASM = nasm +ASM_FLAGS = -f elf64 -g -F dwarf +STACK_FLAGS = -Wl,-z,noexecstack +LD = cc -m64 -g -no-pie $(STACK_FLAGS) +CC = cc +BINARY = arrayfsumc + +all: $(BINARY) + +$(BINARY): arrayfsumc.o arrayfsuma.o + $(LD) -o $@ $^ + +%.o : %.c + $(CC) -m64 -g -c -o $@ $< + +%.o : %.asm + $(NASM) $(ASM_FLAGS) -o $@ $< + +clean: + rm -f *.o $(BINARY) + rm -f *~ + +.PHONY: all clean diff --git a/curs/chap-11-floating-point/arrayfsum/arrayfsuma.asm b/curs/chap-11-floating-point/arrayfsum/arrayfsuma.asm new file mode 100644 index 00000000..cc277efa --- /dev/null +++ b/curs/chap-11-floating-point/arrayfsum/arrayfsuma.asm @@ -0,0 +1,30 @@ +; SPDX-License-Identifier: BSD-3-Clause + + +section .text + +global array_fsum + + +; double array_fsum(double *value, int size) +; rdi = value +; esi = size +; xmm0 = return value +array_fsum: + ; xorpd is a fast idiom to set xmm0 to +0.0. + ; We accumulate in xmm0 because FP return values use xmm0 in SysV ABI. + xorpd xmm0, xmm0 + xor eax, eax + +.add_loop: + cmp eax, esi + jge .done + + ; addsd performs scalar double-precision add: sum += value[i]. + ; We use SSE scalar ops (xmm) instead of x87 stack math for modern x64 code. + addsd xmm0, [rdi + rax * 8] + inc eax + jmp .add_loop + +.done: + ret \ No newline at end of file diff --git a/curs/chap-11-floating-point/arrayfsum/arrayfsuma.h b/curs/chap-11-floating-point/arrayfsum/arrayfsuma.h new file mode 100644 index 00000000..f67fc5df --- /dev/null +++ b/curs/chap-11-floating-point/arrayfsum/arrayfsuma.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef ARRAYFSUMA_H +#define ARRAYFSUMA_H + +double array_fsum(double *value, int size); + +#endif diff --git a/curs/chap-11-floating-point/arrayfsum/arrayfsumc.c b/curs/chap-11-floating-point/arrayfsum/arrayfsumc.c new file mode 100644 index 00000000..e14179f7 --- /dev/null +++ b/curs/chap-11-floating-point/arrayfsum/arrayfsumc.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * This program reads SIZE values into an array and calls + * an assembly language program to compute the array sum. + * The assembly program is in the file "arrayfsuma.asm". + */ + +#include +#include "arrayfsuma.h" + +#define SIZE 10 + +int main(void) +{ + double value[SIZE]; + int i; + + printf("Input %d array values:\n", SIZE); + for (i = 0; i < SIZE; i++) + scanf("%lf", &value[i]); + + printf("Array sum = %lf\n", array_fsum(value, SIZE)); + + return 0; +} diff --git a/curs/chap-11-floating-point/arrayfsum_inline/Makefile b/curs/chap-11-floating-point/arrayfsum_inline/Makefile new file mode 100644 index 00000000..61c97ee2 --- /dev/null +++ b/curs/chap-11-floating-point/arrayfsum_inline/Makefile @@ -0,0 +1,14 @@ +CC = cc +STACK_FLAGS = -Wl,-z,noexecstack +BINARY = arrayfsum_inline.o + +all: $(BINARY) + +%.o : %.c + $(CC) -m64 -g -c -o $@ $< + +clean: + rm -f *.o + rm -f *~ + +.PHONY: all clean diff --git a/curs/chap-11-floating-point/arrayfsum_inline/arrayfsum_inline.c b/curs/chap-11-floating-point/arrayfsum_inline/arrayfsum_inline.c new file mode 100644 index 00000000..421ea9e0 --- /dev/null +++ b/curs/chap-11-floating-point/arrayfsum_inline/arrayfsum_inline.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Inline assembly variant for array summation using x87 instructions. + */ + +double array_fsum(double *value, int size) +{ + double sum; + + asm("fldz; " + "add_loop: jrcxz done; " + "decq %%rcx; " + "faddl (%%rbx, %%rcx, 8); " + "jmp add_loop; " + "done: " + : "=t"(sum) + : "b"(value), "c"((long)size) + : "cc"); + + return sum; +} diff --git a/curs/chap-11-floating-point/fp_representation/Makefile b/curs/chap-11-floating-point/fp_representation/Makefile new file mode 100644 index 00000000..6d06cfb3 --- /dev/null +++ b/curs/chap-11-floating-point/fp_representation/Makefile @@ -0,0 +1,20 @@ +CC = cc +STACK_FLAGS = -Wl,-z,noexecstack +LD = cc -m64 -g -no-pie $(STACK_FLAGS) +BINARIES = fp-m64 fp-m64-O2 + +all: $(BINARIES) + +fp-m64-O2: fp_representation.c + $(CC) -m64 -O2 $(STACK_FLAGS) -o $@ $^ + $(CC) -m64 -O2 -S -masm=intel -o fp-m64-O2.s $< + +fp-m64: fp_representation.c + $(CC) -m64 $(STACK_FLAGS) -o $@ $^ + $(CC) -m64 -S -masm=intel -o fp-m64.s $< + +clean: + rm -f $(BINARIES) *.s + rm -f *~ + +.PHONY: all clean diff --git a/curs/chap-11-floating-point/01-all-demos/fp_representation.c b/curs/chap-11-floating-point/fp_representation/fp_representation.c similarity index 76% rename from curs/chap-11-floating-point/01-all-demos/fp_representation.c rename to curs/chap-11-floating-point/fp_representation/fp_representation.c index 603d19d9..ec35013a 100644 --- a/curs/chap-11-floating-point/01-all-demos/fp_representation.c +++ b/curs/chap-11-floating-point/fp_representation/fp_representation.c @@ -1,5 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause + /* - Se compilează în 3 variante: -m32, -O2 -m32, -m64 + * Demonstrates floating-point representation effects: + * - Decimal-to-binary approximation errors + * - Non-associativity in floating-point arithmetic + * - Precision loss at large magnitudes */ #include diff --git a/curs/chap-11-floating-point/quad/Makefile b/curs/chap-11-floating-point/quad/Makefile new file mode 100644 index 00000000..47f6ac09 --- /dev/null +++ b/curs/chap-11-floating-point/quad/Makefile @@ -0,0 +1,23 @@ +NASM = nasm +ASM_FLAGS = -f elf64 -g -F dwarf +STACK_FLAGS = -Wl,-z,noexecstack +LD = cc -m64 -g -no-pie $(STACK_FLAGS) +CC = cc +BINARY = quadc + +all: $(BINARY) + +$(BINARY): quadc.o quada.o + $(LD) -o $@ $^ + +%.o : %.c + $(CC) -m64 -g -c -o $@ $< + +%.o : %.asm + $(NASM) $(ASM_FLAGS) -o $@ $< + +clean: + rm -f *.o $(BINARY) + rm -f *~ + +.PHONY: all clean diff --git a/curs/chap-11-floating-point/quad/quada.asm b/curs/chap-11-floating-point/quad/quada.asm new file mode 100644 index 00000000..6ee7b943 --- /dev/null +++ b/curs/chap-11-floating-point/quad/quada.asm @@ -0,0 +1,71 @@ +; SPDX-License-Identifier: BSD-3-Clause + + +section .rodata + + two dq 2.0 + four dq 4.0 + + +section .text + +global quad_roots + + +; int quad_roots(double a, double b, double c, double *root1, double *root2) +; xmm0 = a, xmm1 = b, xmm2 = c +; rdi = root1, rsi = root2 +; eax = 1 if real roots exist, 0 otherwise +quad_roots: + ; discriminant = b * b - 4 * a * c + ; Copy b from xmm1 to xmm3 so we keep input registers available. + movapd xmm3, xmm1 + ; mulsd = scalar double multiply (low 64 bits): xmm3 = b * b. + mulsd xmm3, xmm1 + + ; Build 4*a*c in xmm4. + movapd xmm4, xmm0 + mulsd xmm4, xmm2 + mulsd xmm4, [rel four] + + ; xmm3 now holds the discriminant delta. + subsd xmm3, xmm4 + + ; If discriminant < 0, there are no real roots. + ; xorpd zeroes xmm4; this gives us 0.0 for the comparison. + xorpd xmm4, xmm4 + ; ucomisd compares two scalar doubles and sets CPU flags for jb/jbe/jae. + ucomisd xmm3, xmm4 + jb .no_real_roots + + ; sqrtsd computes sqrt(delta) in scalar double precision. + sqrtsd xmm4, xmm3 + + ; denominator = 2 * a + movapd xmm5, xmm0 + mulsd xmm5, [rel two] + + ; base = -b + ; Build -b as (0.0 - b) without touching the original b in xmm1. + xorpd xmm6, xmm6 + subsd xmm6, xmm1 + + ; root1 = (-b + sqrt(discriminant)) / (2 * a) + movapd xmm7, xmm6 + addsd xmm7, xmm4 + divsd xmm7, xmm5 + ; movsd stores one scalar double to *root1. + movsd [rdi], xmm7 + + ; root2 = (-b - sqrt(discriminant)) / (2 * a) + subsd xmm6, xmm4 + divsd xmm6, xmm5 + ; Pointers to outputs are in integer registers (rdi/rsi), data is in xmm regs. + movsd [rsi], xmm6 + + mov eax, 1 + ret + +.no_real_roots: + xor eax, eax + ret \ No newline at end of file diff --git a/curs/chap-11-floating-point/quad/quada.h b/curs/chap-11-floating-point/quad/quada.h new file mode 100644 index 00000000..0503d79b --- /dev/null +++ b/curs/chap-11-floating-point/quad/quada.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef QUADA_H +#define QUADA_H + +int quad_roots(double a, double b, double c, + double *root1, double *root2); + +#endif diff --git a/curs/chap-11-floating-point/quad/quadc.c b/curs/chap-11-floating-point/quad/quadc.c new file mode 100644 index 00000000..f0965ce7 --- /dev/null +++ b/curs/chap-11-floating-point/quad/quadc.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * This program reads three constants (a, b, c) and calls an + * assembly language program to compute the roots of the + * quadratic equation. + * The assembly program is in the file "quada.asm". + */ + +#include +#include "quada.h" + +int main(void) +{ + double a, b, c, root1, root2; + + printf("Enter quad constants a, b, c: "); + scanf("%lf %lf %lf", &a, &b, &c); + + if (quad_roots(a, b, c, &root1, &root2)) + printf("Root1 = %lf and root2 = %lf\n", root1, root2); + else + printf("There are no real roots.\n"); + + return 0; +}