🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.asm
1 messages
1 total messages Started by Lech Lorens Wed, 14 Feb 2007 01:18
x86 - błąd przy ładowaniu liczby zmiennoprzecinkowej
#993
Author: Lech Lorens
Date: Wed, 14 Feb 2007 01:18
140 lines
3811 bytes
Mam program w C:

#v+
#include <stdio.h>
unsigned square_roots(double, double, double, double*, double*);
void display_roots(unsigned n, double r1, double r2)
{
	switch(n)
	{
		case 2:
			printf("(%lf, %lf)\n", r1, r2);
			break;
		case 1:
			printf("(%lf)\n", r1);
			break;
		default:
			printf("()\n");
			break;
	}
}
int main(int argc, char **argv)
{
	unsigned nroots;
	double r1, r2;
	r1 = r2 = 0;
	nroots = square_roots(4.0, 0.0, -16.0, &r1, &r2);
	printf("nroots = %u\n", nroots);
	display_roots(nroots, r1, r2);

	nroots = square_roots(1.0l, 8.0l, 16.0l, &r1, &r2);
	printf("nroots = %u\n", nroots);
	display_roots(nroots, r1, r2);

	return 0;
}
#v-

Program przy pomocy funkcji square_roots() liczy pierwiastki równania
kwadratowego. Te pierwiastki są zapisywane w zmiennych r1 i r2. Funkcja
square_roots() jest napisana w asemblerze x86 (w osobnym pliku):

#v+
section .data
	MinusFour	dw	-4

section .text
	global square_roots

; unsigned square_root(double a, double b, double c, double *r1, double *r2);
; liczy pierwiastki równania kwadratowego a*x^2 + b*x + c = 0
; zwraca liczbę różnych rzeczywistych pierwiastków
%define a qword [ebp + 8]
%define b qword [ebp + 16]
%define c qword [ebp + 24]
square_roots:
	push ebp
	mov ebp, esp
	sub esp, 16

	fild word [MinusFour]
	fld a
	fld c		; c, a, -4
	fmulp st1	; c * a
	fmulp st1	; -4 * a * c
	fld b		; b, -4 * a * c
	fmul st0
	faddp st1	; b * b - 4 * a * c
	ftst
	fstsw ax
	sahf
	ja two_roots
	je single_root
	jmp no_roots

two_roots:
	fsqrt
	fst qword [ebp - 8]	; załaduj wyróżnik do ebp - 8

	fld1
	fld a
	fscale
	fst qword [ebp - 16]

	fld b
	fchs
	fsub qword [ebp - 8]
	fdiv qword [ebp - 16]
	mov eax, [ebp + 32]	; adres zmiennej r1 do eax
	fst qword [eax]

	fld b
	fchs
	fadd qword [ebp - 8]
	fdiv qword [ebp - 16]
	mov eax, [ebp + 36]	; adres zmiennej r2 do eax
	fst qword [eax]

	mov eax, 2
	jmp end_square_roots

single_root:
	fld1
	fld a
	fscale

	fld b			; PROBLEM - ładuje się NaN
	fchs
	fdiv st1
	mov eax, [ebp + 32]	; adres zmiennej r1 do eax
	fst qword [eax]
	mov eax, [ebp + 36]	; adres zmiennej r2 do eax
	fst qword [eax]

	mov eax, 1
	jmp end_square_roots
no_roots:
	xor eax, eax

end_square_roots:
	mov esp, ebp
	pop ebp
	ret
#v-

Wynik dla pierwszego wywołania square_roots() jest poprawny - zostają
wyliczone dwa pierwiastki: -2.0 i 2.0. Wynik dla drugiego wywołania nie
jest poprawny - do zmiennych r1 i r2 zostaje przypisane NaN. Dzieje się
tak dlatego, że instrukcja fld b z linii oznaczonej komentarzem
"PROBLEM" powoduje załadowanie do rejestru st0 NaN.

Program w C kompiluję przy pomocy gcc 4.1, plik w asemblerze asembluję
przy pomocy NASM-a. Debugowałem program przy pomocy gdb, oczywiście pod
adresem, z którego jest odczytywana liczba znajduje się poprawna wartość
(8.0).

Co robię źle? Z góry dziękuję za pomoc!

-- 
Pozdrawiam,
Lech Lorens - lp.pw@snerol_hcel
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads