Ajuda em assembly

Bom dia!

Pessoal tenho que realizar a raiz quadrada de um numero em assembler exemplo raiz quadrada de 9 resultado 3,0 não consigo fazer esta programação SQRT que é o codigo da raiz não funciona estou pedindo a ajuda de todos, sugestões e criticas serão bem vindos, só quero deixar claro que este é meu segundo programa em assembler não tenho conhecimento nesta programação mas estou correndo atrás.

Nesse link você encontra ajuda.
http://blog.datek.com.br/2011/09/12/raiz-quadrada-em-assembler-para-pic/

Fica complicado ajudar você, pois não sabemos qual arquitetura você está usando.

Creio que com isso você possa pensar e acabar resolvendo o problema na arquitetura que estiver utilizando:

raiz de 16 = ?
1º Passo 16 − 1 = 15
2º Passo 15 − 3 = 12
3º Passo 12 − 5 = 7
4º Passo 7 − 7 = 0

O resultado da raiz quadrada é o contador => 4

Se chegar em 0 é porque temos uma raiz quadrada perfeita.

Porque estou utilizando 1,3,5,7 ?

indice * 2 + 1
1º Passo => 0 * 2 + 1 => 1
2º Passo => 1 * 2 + 1 => 3
3º Passo => 2 * 2 + 1 => 5

Creio que dessa forma fique mais fácil, pois você tem uma forma matemática para cálculo de raiz quadrada.

1 curtida

estou usando o emu 8086, testei todos os codigos que passaram do site e não funciona.

[quote=Divinotoledo]Bom dia!

Pessoal tenho que realizar a raiz quadrada de um numero em assembler exemplo raiz quadrada de 9 resultado 3,0 não consigo fazer esta programação SQRT que é o codigo da raiz não funciona estou pedindo a ajuda de todos, sugestões e criticas serão bem vindos, só quero deixar claro que este é meu segundo programa em assembler não tenho conhecimento nesta programação mas estou correndo atrás.[/quote]

Dica: uma forma de você escrever um programa em Assembly é sempre testar o algoritmo antes em Java ou C, antes de sair escrevendo.

Uma vez que o algoritmo funciona em Java ou C, você pode passá-lo “mecanicamente” para Assembly sem muitos problemas.

para terem uma ideia este é o codigo que estou usando para calculadora.

name “calc2”

; command prompt based simple calculator (+,-,*,/) for 8086.
; example of calculation:
; input 1 <- number: 10
; input 2 <- operator: -
; input 3 <- number: 5
; -------------------
; 10 - 5 = 5
; output -> number: 5

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; this maro is copied from emu8086.inc ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; this macro prints a char in AL and advances
; the current cursor position:
PUTC MACRO char
PUSH AX
MOV AL, char
MOV AH, 0Eh
INT 10h
POP AX
ENDM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

org 100h

jmp start

; define variables:

msg0 db “note: calculator works with integer values only.”,0Dh,0Ah
db “to learn how to output the result of a float division see float.asm in examples”,0Dh,0Ah,’$'
msg1 db 0Dh,0Ah, 0Dh,0Ah, 'enter first number: $'
msg2 db "enter the operator: + - * / : $"
msg3 db "enter second number: $“
msg4 db 0dh,0ah , 'the approximate result of my calculations is : $'
msg5 db 0dh,0ah ,'thank you for using the calculator! press any key… ', 0Dh,0Ah, '$'
err1 db “wrong operator!”, 0Dh,0Ah , '$'
smth db " and something… $”

; operator can be: ‘+’,’-’,’*’,’/’ or ‘q’ to exit in the middle.
opr db ‘?’

; first and second number:
num1 dw ?
num2 dw ?

start:
mov dx, offset msg0
mov ah, 9
int 21h

lea dx, msg1
mov ah, 09h ; output string at ds:dx
int 21h

; get the multi-digit signed number
; from the keyboard, and store
; the result in cx register:

call scan_num

; store first number:
mov num1, cx

; new line:
putc 0Dh
putc 0Ah

lea dx, msg2
mov ah, 09h ; output string at ds:dx
int 21h

; get operator:
mov ah, 1 ; single char input to AL.
int 21h
mov opr, al

; new line:
putc 0Dh
putc 0Ah

cmp opr, ‘q’ ; q - exit in the middle.
je exit

cmp opr, '*'
jb wrong_opr
cmp opr, '/'
ja wrong_opr

; output of a string at ds:dx
lea dx, msg3
mov ah, 09h
int 21h

; get the multi-digit signed number
; from the keyboard, and store
; the result in cx register:

call scan_num

; store second number:
mov num2, cx

lea dx, msg4
mov ah, 09h ; output string at ds:dx
int 21h

; calculate:

cmp opr, '+'
je do_plus

cmp opr, '-'
je do_minus

cmp opr, '*'
je do_mult

cmp opr, '/'
je do_div

; none of the above…
wrong_opr:
lea dx, err1
mov ah, 09h ; output string at ds:dx
int 21h

exit:
; output of a string at ds:dx
lea dx, msg5
mov ah, 09h
int 21h

; wait for any key…
mov ah, 0
int 16h

ret ; return back to os.

do_plus:

mov ax, num1
add ax, num2
call print_num ; print ax value.

jmp exit

do_minus:

mov ax, num1
sub ax, num2
call print_num ; print ax value.

jmp exit

do_mult:

mov ax, num1
imul num2 ; (dx ax) = ax * num2.
call print_num ; print ax value.
; dx is ignored (calc works with tiny numbers only).

jmp exit

do_div:
; dx is ignored (calc works with tiny integer numbers only).
mov dx, 0
mov ax, num1
idiv num2 ; ax = (dx ax) / num2.
cmp dx, 0
jnz approx
call print_num ; print ax value.
jmp exit
approx:
call print_num ; print ax value.
lea dx, smth
mov ah, 09h ; output string at ds:dx
int 21h
jmp exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; these functions are copied from emu8086.inc ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; gets the multi-digit SIGNED number from the keyboard,
; and stores the result in CX register:
SCAN_NUM PROC NEAR
PUSH DX
PUSH AX
PUSH SI

    MOV     CX, 0

    ; reset flag:
    MOV     CS:make_minus, 0

next_digit:

    ; get char from keyboard
    ; into AL:
    MOV     AH, 00h
    INT     16h
    ; and print it:
    MOV     AH, 0Eh
    INT     10h

    ; check for MINUS:
    CMP     AL, '-'
    JE      set_minus

    ; check for ENTER key:
    CMP     AL, 0Dh  ; carriage return?
    JNE     not_cr
    JMP     stop_input

not_cr:

    CMP     AL, 8                   ; 'BACKSPACE' pressed?
    JNE     backspace_checked
    MOV     DX, 0                   ; remove last digit by
    MOV     AX, CX                  ; division:
    DIV     CS:ten                  ; AX = DX:AX / 10 (DX-rem).
    MOV     CX, AX
    PUTC    ' '                     ; clear position.
    PUTC    8                       ; backspace again.
    JMP     next_digit

backspace_checked:

    ; allow only digits:
    CMP     AL, '0'
    JAE     ok_AE_0
    JMP     remove_not_digit

ok_AE_0:
CMP AL, '9’
JBE ok_digit
remove_not_digit:
PUTC 8 ; backspace.
PUTC ’ ’ ; clear last entered not digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for next input.
ok_digit:

    ; multiply CX by 10 (first time the result is zero)
    PUSH    AX
    MOV     AX, CX
    MUL     CS:ten                  ; DX:AX = AX*10
    MOV     CX, AX
    POP     AX

    ; check if the number is too big
    ; (result should be 16 bits)
    CMP     DX, 0
    JNE     too_big

    ; convert from ASCII code:
    SUB     AL, 30h

    ; add AL to CX:
    MOV     AH, 0
    MOV     DX, CX      ; backup, in case the result will be too big.
    ADD     CX, AX
    JC      too_big2    ; jump if the number is too big.

    JMP     next_digit

set_minus:
MOV CS:make_minus, 1
JMP next_digit

too_big2:
MOV CX, DX ; restore the backuped value before add.
MOV DX, 0 ; DX was zero before backup!
too_big:
MOV AX, CX
DIV CS:ten ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
MOV CX, AX
PUTC 8 ; backspace.
PUTC ’ ’ ; clear last entered digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for Enter/Backspace.

stop_input:
; check flag:
CMP CS:make_minus, 0
JE not_minus
NEG CX
not_minus:

    POP     SI
    POP     AX
    POP     DX
    RET

make_minus DB ? ; used as a flag.
SCAN_NUM ENDP

; this procedure prints number in AX,
; used with PRINT_NUM_UNS to print signed numbers:
PRINT_NUM PROC NEAR
PUSH DX
PUSH AX

    CMP     AX, 0
    JNZ     not_zero

    PUTC    '0'
    JMP     printed

not_zero:
; the check SIGN of AX,
; make absolute if it’s negative:
CMP AX, 0
JNS positive
NEG AX

    PUTC    '-'

positive:
CALL PRINT_NUM_UNS
printed:
POP AX
POP DX
RET
PRINT_NUM ENDP

; this procedure prints out an unsigned
; number in AX (not just a single digit)
; allowed values are from 0 to 65535 (FFFF)
PRINT_NUM_UNS PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX

    ; flag to prevent printing zeros before number:
    MOV     CX, 1

    ; (result of "/ 10000" is always less or equal to 9).
    MOV     BX, 10000       ; 2710h - divider.

    ; AX is zero?
    CMP     AX, 0
    JZ      print_zero

begin_print:

    ; check divider (if zero go to end_print):
    CMP     BX,0
    JZ      end_print

    ; avoid printing zeros before number:
    CMP     CX, 0
    JE      calc
    ; if AX<BX then result of DIV will be zero:
    CMP     AX, BX
    JB      skip

calc:
MOV CX, 0 ; set flag.

    MOV     DX, 0
    DIV     BX      ; AX = DX:AX / BX   (DX=remainder).

    ; print last digit
    ; AH is always ZERO, so it's ignored
    ADD     AL, 30h    ; convert to ASCII code.
    PUTC    AL


    MOV     AX, DX  ; get remainder from last div.

skip:
; calculate BX=BX/10
PUSH AX
MOV DX, 0
MOV AX, BX
DIV CS:ten ; AX = DX:AX / 10 (DX=remainder).
MOV BX, AX
POP AX

    JMP     begin_print

print_zero:
PUTC ‘0’

end_print:

    POP     DX
    POP     CX
    POP     BX
    POP     AX
    RET

PRINT_NUM_UNS ENDP

ten DW 10 ; used as multiplier/divider by SCAN_NUM & PRINT_NUM_UNS.

GET_STRING PROC NEAR
PUSH AX
PUSH CX
PUSH DI
PUSH DX

MOV CX, 0 ; char counter.

CMP DX, 1 ; buffer too small?
JBE empty_buffer ;

DEC DX ; reserve space for last zero.

;============================
; Eternal loop to get
; and processes key presses:

wait_for_key:

MOV AH, 0 ; get pressed key.
INT 16h

CMP AL, 0Dh ; ‘RETURN’ pressed?
JZ exit_GET_STRING

CMP AL, 8 ; ‘BACKSPACE’ pressed?
JNE add_to_buffer
JCXZ wait_for_key ; nothing to remove!
DEC CX
DEC DI
PUTC 8 ; backspace.
PUTC ’ ’ ; clear position.
PUTC 8 ; backspace again.
JMP wait_for_key

add_to_buffer:

    CMP     CX, DX          ; buffer is full?
    JAE     wait_for_key    ; if so wait for 'BACKSPACE' or 'RETURN'...

    MOV     [DI], AL
    INC     DI
    INC     CX
    
    ; print the key:
    MOV     AH, 0Eh
    INT     10h

JMP wait_for_key
;============================

exit_GET_STRING:

; terminate by null:
MOV [DI], 0

empty_buffer:

POP DX
POP DI
POP CX
POP AX
RET
GET_STRING ENDP

Você pode usar o método babilônio para calcular a raiz.
Não sei dizer como isso ficaria em assembly pois desconhece a linguagem.

Veja o link da wikipédia.

http://pt.wikipedia.org/wiki/Raiz_quadrada#Calculadoras

A raiz quadrada é de um número inteiro de 32 bits?

sim a raiz quadrada é de um numero inteiro de 32 bitz

Dica:
a) Implemente o método babilônio (que é o que lhe indicaram) em C ou Java, para ver se você entendeu corretamente o algoritmo dado na Wikipedia.
b) Converta esse pedaço do programa em C ou Java para Assembly.

tranquilo o codigo em c é este:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

/*
raiz quadrada de um numero
*/

int main(){
float num, raiz;
printf(“Digite um numero: \t”);
scanf("%f",&num);
raiz = sqrt(num);
printf(“A raiz quadrada de %f é: %f.\n”, num, raiz);
system(“pause”);
return 0;
}

agora como converto?

Eu também fiquei em dúvida de como se dá o processe de conversão “mecanizada” java/c para assembly.

Acho que a ideia é implementar o método babilônio e não utilizar a função sqrt do c.

o metodo babilonioo do c é este, não é isto mas e como converter?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double mySqrt (int n, int numCasasDecimais);
double pot(int n);
int main()
{
int Decimais,n;

printf("Numero a calcular raiz\n");
scanf("%d",&n);
printf("casas decimais?\n");
scanf("%d",&Decimais);
mySqrt(n,Decimais);

}
double mySqrt (int n, int numCasasDecimais){
double x1; /x1 em termos de contexto funciona como o Xn-1/
double x2; /x2 em termos de contexto funciona como o Xn/
double w;
x1=n/2;
x2=((x1+(n/x1))/2);
do
{
x1=x2;
x2=((x1+(n/x1))/2);
w=x2-x1;
if (w<0){
w=-1*w;}
}
while (w>pot(numCasasDecimais));
printf("%g",x2);
}

double pot(int n) {
double value = 1;
if (n < 0)
return 0; /* 0 indicates error */
while (n!=0) {
value /= 10;
n–;
}
return value;
}

Você sabe como fazer um do/while em assembly? A primeira coisa a fazer é converter o do/while em uma série de gotos.

O que eu chamo de “conversão mecanizada” é o seguinte.

  1. Escreva o programa em C (sem usar as bibliotecas, é claro) que faça o que você quer fazer. (Dica: se for fazer o programa em C, use o máximo de variáveis globais possível - você vai entender por quê).

  2. Converta esse programa em um fluxograma (para ficar fácil de você ver onde é necessário usar JMP ou JE ou outras operações condicionais, e onde devem ficar os labels).

  3. Uma vez feito isso, verifique como é que você converte as variáveis em C do seu programa em registradores ou então em posições de memória no seu programa em Assembly. (As variáveis globais podem corresponder àquelas posições de memória que eu falei no item 1).

Se você prefere usar variáveis locais em vez de globais, então associe as variáveis locais a registradores ou então a posições de memória no stack (o endereçamento preferido é usando o registrador BP, no caso de 16 bits, EBP, no caso de 32 bits, ou então RBP no caso de 64 bits.

Só mais uma coisinha.

Você fez as contas com double (ou seja, precisa usar a FPU ou então aquelas instruções SSE3).

Não é melhor você acertar seu algoritmo para funcionar com int mesmo? É que sua calculadora só trabalha com números inteiros, e converter um número de ponto flutuante em uma string em Assembly é algo extremamente não-trivial (o algoritmo em C já é grande, imagine em Assembly).

Tinha me esquecido que você pode calcular a raiz quadrada, em uma máquina Intel/AMD, usando a instrução fsqrt.

Veja um exemplo em:
http://en.wikibooks.org/wiki/X86_Assembly/Floating_Point

No seu caso, você pode converter o seu número de 32 bits em um número de ponto-flutuante de 80 bits, extrair a raiz quadrada, e então reconverter o número para um inteiro.

resolvido o codigo raiz quadrada em assembler

Resolvido o programa em assembly da raiz quadrada

Toledo-san, o que você usou?

a) FSQRT
b) O algoritmo das aproximações sucessivas