Ensamblador - Combinaciones en copro

 
Vista:

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 01/03/2014 01:44:22
He hecho una macro para calcular combinaciones matemáticas en modo convencional y tengo unas dudas para pasarlo a lenguaje de copro.
Quisiera poder calcular combinaciones, por ejemplo, de 3000 elementos de 10 en 10. Esto no me es posible dado lo enorme del resultado.
Cómo, dónde almacenaría el resultado para luego, por ejemplo, convertirlo a ASCII?. Cómo lo pasaría a ASCII?
Gracias aunque no tenga respuesta.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
NumCombis   macro   a,b
local   otra,fuera,otra2
;                           Entrada: a=numeros, b=tipo combinaciones
;                           Salida: eax=total combinaciones
;                           combinaciones de a elementos tomados de b en b
;                           Combinaciones de 30 de 6 en 6
;                           NumCombis 30,6
        push    ebx
        push    ecx
        push    edx
 
        xor     edx,edx
        mov     ebx,a
        sub     ebx,b
 
        inc     ebx         ; ebx=24 +1 =25
        mov     ecx,a       ; ecx=30
        mov     eax,ecx     ; eax=30
        dec     ecx         ; ecx=29
otra:
        cmp     ecx,ebx     ; ecx=ebx ?
        jb      fuera       ; si es menor, sale del bucle
        mul     ecx         ; multiplica eax por ecx 30x29x28x27x26x25
        dec     ecx         ; resta 1 a ecx
        jmp     otra        ; salta a la comparacion
fuera:
        push    eax         ; guarda en la pila el resultado
        push    edx
        mov     ecx,b       ; ecx=6
        mov     eax,ecx     ; eax=6
        dec     ecx         ; ecx= 5
otra2:
        mul     ecx         ; multiplica eax por ecx 5 veces  6x5x4x3x2
        loop    otra2
        mov     ecx,eax     ; ecx= eax = 6x5x4x3x2
        pop     edx         ; saco de la pila  30x29x28x27x26x25
        pop     eax
        div     ecx         ; lo divido por 6x5x4x3x2
 
        pop     edx
        pop     ecx
        pop     ebx
        endm                ; el resultado esta en eax
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 02/03/2014 07:50:50
Yo metería el resultado en un archivo.

Para transformarlo a ascii puedes usar las instrucciones de ajuste ascii. Hay unas cuantas, y tendrás que usar la que mejor te vaya.

Por ejemplo, si tienes en al un 23, que es un número hex, tras un aam tienes en ah un 3 y en al un 5. Tras un or ax, 3030h, tienes en ax un 3335, que es el número hex 23 en decimal ascii.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 02/03/2014 20:36:20
Me refiero a, si logro hacer en el copro, no se como, el resultado enorme que es de combinaciones de 3000 elementos de 10 en 10, en donde lo guardo. No entra en edx:eax por ejemplo. En memoria seria en torno a 5,9e + 34. Convertir a ASCII el contenido de EDX:EAX es sencillo. Cómo guardaría el copro el resultado?. Y luego vendría la conversión. Me refiero a números mayores de 64 bits.
Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 03/03/2014 21:50:46
Sí, me parece que no te entiendo del todo.

Dices combinaciones de 3000 elementos cogidos de 10 en 10, ¿no?. Hablamos entonces de 10 elementos en total, no sé lo que ocupará cada uno. Si son bytes, un número de 10 bytes cabe en un registro del coprocesador.

Todas las combinaciones, como mucho, van a caberte en el disco duro, no en memoria. Las operaciones que haces para convertir edx:eax a ascii te valen también para convertir lo que haya en un registro de 128 bits del coprocesador a ascii.

No sé si es eso.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 04/03/2014 04:20:09
Creo que no me he explicado bien.
Programo con un ordenador de 32 bits.
Lo que necesito es el nº de combinaciones, no el desarrollo de las combinaciones.
Con 32 bits puedo almacenar un nº en EDX:EAX de 2^64 como máximo. Lo puedo guardar en una variable en memoria y luego utilizarlo volviendo a cargarlo en EDX:EAX.
He puesto combinaciones de 3000 de 10 en 10 pero pudieran ser combinaciones de 20000 de 15 en 15.
Con el copro podria calcular el nº y acto seguido convertirlo en ASCII y guardarlo en memoria en ASCII.
Lo que necesito es guardarlo en memoria en hexadecimal para hacer otros cálculos y mas tarde convertirlo a ASCII.
Cuando cargas en EAX por ejemplo cargas un dword. (mov EAX, dword ptr lo que sea).
No se como se carga y se guarda en memoria el registro del copro. Qué tamaño tendría la variable? Si después de hacer varias operaciones, el nº final fuese 15 y está en la variable en que guardé el resultado del registro del copro, qué estructura sigue para cargar el resultado en EAX, o AX o AL.
Una variable dword la puedo cargar en EAX y manejarla con AL si es 1 byte, pero con el copro, ni idea.
Gracias de nuevo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 04/03/2014 08:52:27
Entonces lo único que necesitas es manejar números muy grandas. Creí que estabas sacando las contraseñas de 128 bits del vecino.

Un procesador de ahora puede manejar núneros de 128 bits. Con la misma idea que manejas números de 64 bits con edx:eax podrás manejar números de 256 bits, juntando 2 registros de 128 bits.

Así que lo que tienes que mirarte son las instrucciones SIMD. http://www.ciciliani.com.ar/datos/SIMD%20la%20cuarta%20dimension_2010-04-20.MMX-SSE.pdf.

Un registro de 128 bits se guarda igual que uno de 32. Se empieza en el byte que le pases y va ocupando bytes consecutivos hasta los 16 que necesita, en una variable que es un tword.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 04/03/2014 11:05:02
Oword, un tword son 80 bits.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 07/03/2014 01:10:08
Nada, con el copro solo consigo/se conseguir 18 dígitos.
Seguiré estudiando.
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
.model small
      .386
.code
empieza:
JMP     inicio2
CR equ 13
LF equ 10
a           dw     1800     ; cifras para el ejemplo
b           dw     6
resultado   dq     ?
resultado2  dt     ?
AscBuf      DB     20 dup(0),CR,LF, '$'  ;20  digitos
AscBuf2     db     20 dup(0),CR,LF, '$'
inicio2 proc
push    cs
pop     ds
push    cs
pop     es
            fild    word ptr a
            mov     cx,b
            dec     ecx
loop1:      dec     a
            fild     word ptr a
            fmul
            fild    word ptr b
            fdiv
            dec     b
            loop    loop1
            fst     st(1)               ;duplico resultado para tener dos opciones
            fistp    resultado          ; Entero 64 bits
            fbstp   resultado2          ; BCD empaquetado
            fwait
; --------------------------Rutina para BCD empaquetado a ASCII---------
            lea     esi,resultado2      ;paso del signo porque es positivo
            lea     edi,AscBuf2 +18
            mov     ecx,9
            std
mas:        mov     al,byte ptr [esi]
            xor     ah,ah
            ror     ax,4
            ror     ah,4
            add     ax,03030h
            stosw
            inc     esi
            loop    mas
            cld
            xor     edx,edx
            xor     eax,eax
            lea     dx,AscBuf2
            mov     ah,09h
            int     21h
 
; ---------Esto es para convertir a ASCII con cualquier rutina--- para 64 bits claro--
 
mov     eax,dword ptr resultado
mov     edx,dword ptr resultado +4
call    Asc64
xor     edx,edx
xor     eax,eax
lea     dx,AscBuf
mov     ah,09h
int     21h
 
mov ax,4c00h
int 21h
inicio2 endp
include 64bitsAscii.asm         ;proc para convertir a ASCII 64 bits
end empieza
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 07/03/2014 12:48:33
Con 64 bits consigues 20 dígitos en decimal. Con el coprocesador estás usando la mantisa de cada registro, que son 64 bits. Ya te digo que puedes usar registros de 128 bits con instruccinones como MOVDQU. La palabrota mueve entre registros xmm, de 128 bits, y la memoria.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 10/03/2014 18:33:26
Gracias pero no tengo MMX.
Estoy haciendo un debug a la calculadora de windows para ver como hace para representar 2^106 = 32 dígitos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 10/03/2014 18:48:09
Las instrucciones de las que hablo las implementó Intel en el 2005. El problema es que las incluya el ensamblador que uses. Tasm no las incluye. Nasm creo que sí. Podrías también meter asm desde un compilador de c moderno.

Sí, la calculadora maneja números gordísimos desde hace mucho, sin SSE ni nada. Se hace igual que un z80 maneja números de 32 bits, por código. Igual que metes un número gordo en edx:eax metes un número más gordo todavía en ecx:edx:eax.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 10/03/2014 19:49:00
Utilizo MASM32.
El tema es que estoy pasando programas que había hecho a principios de los 90 en 8086 a 386 y en entorno Windows. Ya tengo bastante rollo con el tema de las Apis como para meterme en C puesto que en su día cambié a Visual en lugar de C, error, pero bueno, prefiero ensamblador. Si o sí va a salir. Lo que me sobra es paciencia.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Combinaciones en copro

Publicado por Pico (50 intervenciones) el 10/03/2014 19:54:59
Meterte en c no, poner ensamblador desde un compilador de c. Puedes poner todo en asm, hacer un obj y enlazarlo con lo que sea.

Creo que puedes hacer otra cosa. No me he puesto a mirarlo pero con el ensamblador delante se ve enseguida. Yo he usado registros de 32 bits desde código en 16. Con un 66 delante de una instrucción en 16 bits usas registros de 32. Creo recordar que con código en 32 bits, con un procesador de ahora, con un 66 delante usas registros de 64 bits (espero que no use de 16). Con eso tienes un rdx:rax, 128 bits, igual que ahora usas edx:eax.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 12/03/2014 23:51:26
Bueno, ya he resuelto el problema.
He realizado una versión del algoritmo de Schönhage-Strassen para multiplicaciones añadiendo el acarreo en cada pasada para acortar el código.
Lo he probado multiplicando 64 bits x 64 bits x 32 bits x 32 bit x 32 bits y he parado en unos 100 digitos, pero la longitud solo depende de buffer que se ponga para almacenar el resultado.
Ni siquiera hace falta un 386 para que funcione.
No hay nada mejor que estudiar un poco y todo se puede resolver.

Si alguien está interesado, que lo diga y lo subo al foro.

Gracias por todo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de xve

Combinaciones en copro

Publicado por xve (8 intervenciones) el 13/03/2014 09:03:09
Hola Sabino, nos puedes compartir el código?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por sabino (9 intervenciones) el 13/03/2014 13:19:57
Variación del Algoritmo de Schönhage-Strassen para multiplicaciones enormes

.model small
.386
.code
empieza:
JMP inicio2
CR equ 13
LF equ 10
resultado dq 0ffffffffffffffffh ;cifras para el ejemplo
resultado2 dq 0ffffffffffffffffh
IntBuf1 DB 230 dup(0) ;operando1
IntBuf2 DB 24 dup(0) ;operando2
IntBuf3 Db 320 dup(0) ;producto
salida db 230 dup (0) ;almacena cadena de salida
; -------------------------------------------------------------------------
; Variación del Algoritmo de Schönhage-Strassen para multiplicaciones enormes
;Resultado de las multiplicaciones de prueba:
;2135987035920910081816061259982971137547620614667080038315646755056884185109834672074087649509375
; Sabino 12/03/2014
; -------------------------------------------------------------------------

inicio2 proc
push cs
pop ds
push cs
pop es
; ------------------------------Convierte las cifras a enteros (no ascii)--------------
lea edi,IntBuf1
mov eax,dword ptr resultado
mov edx,dword ptr resultado +4
call NoAsc64
lea edi,IntBuf2
mov eax,dword ptr resultado2
mov edx,dword ptr resultado2 +4
call NoAsc64
; -----------------------------Rutina que multiplica------------------------------------
call MulLongInt
call MulLongInt

call MulLongInt
call MulLongInt

; ----------------------------------------Invierte la cadena y conviete a Ascii------------
mov esi,edi ;edi viene de la rutina anterior
dec esi

lea edi,salida
Yavale:
std
lodsb
or al,30h
cld
stosb
loop Yavale
mov byte ptr [edi],'$'
; -------------------------------------------------------------------------
xor edx,edx
xor eax,eax
lea dx,salida
mov ah,09h
int 21h

mov ax,4c00h
int 21h
inicio2 endp
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
MulLongInt proc
lea edi,IntBuf3 ;pongo a 0 la variable/buffer
mov ecx,80 ;del resultado
mov eax,0
rep stosd
; -------------------------------------------------------------------------
xor eax,eax
xor ecx,ecx
lea edx,Intbuf2 ; segundo factor
lea edi,IntBuf3 ; Donde guarda el producto
mov Cl,byte ptr [edx] ; Cl para los enteros del 2º factor
MOV CH,10 ; Cociente
fila0:
lea esi,IntBuf1 ; primer factor
push edi
cld
fila1:
lodsb
cmp al,'$' ;señala fin del factor1,
je N2
mul Cl
add al,byte ptr[edi] ;sumo al que ya tiene el resultado

CMP Al,ch ;menor de 10
Jnb CASI2
MOV byte PTR [EDI],al ; añado al resultado
add edi,1
jmp fila1
CASI2:
DIV CH ;>=10, divido por 10
ror Ax,8
MOV byte PTR [EDI],al ; añado el resto al resultado
add byte ptr [edi+1],ah ; sumo el cociente al siguiente
Xor Ax,ax ; borro para leer otro
add Edi,1
jmp fila1
N2:
inc edx ;siguiente del factor2
mov Cl,byte ptr [edx]
cmp Cl,'$' ;fin del factor2
je saliendo
pop edi
add edi,1
jmp fila0
saliendo:
cmp byte ptr [edi],0 ;si el primero es cero
je bye
inc di
bye:
mov byte ptr [edi],'$' ;marco final del entero
pop edi

; ------------------------------------Copia el producto al operando1 para otro producto-------
lea edi,IntBuf1
lea esi,IntBuf3
xor ecx,ecx
cld
apormas:
lodsb
cmp al,'$'
je dalavuelta
add ecx,1 ;contador de dígitos
stosb
jmp apormas

dalavuelta:
mov byte ptr [edi],'$'
ret
MulLongInt endp
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤

NoAsc64 PROC ;convierte a entero
cld ;el registro/s pasado
mov ecx,edx ;de izquierda a derecha.
xchg eax,esi
mov ebx,100

Asc64a: xor edx,edx
xchg eax,ecx
div ebx
xchg eax,ecx
xchg eax,esi
div ebx
xchg eax,esi
xchg eax,edx
aam
stosw
mov eax,ecx
or eax,esi
jnz Asc64a
sub edi,1
cmp byte ptr[edi],0
jz Asc64b
inc edi
Asc64b: mov byte ptr[edi],'$' ;marca final del entero
ret

NoAsc64 ENDP

end empieza
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Combinaciones en copro

Publicado por MSH (120 intervenciones) el 30/03/2014 23:06:56
Que tal Sabino.

El mejor código de ensamblador que he visto por aquí en años,de lejos. En realidad, me llamó la atención este comentario:

"...El tema es que estoy pasando programas que había hecho a principios de los 90 en 8086 a 386 y en entorno Windows..."

¿Tendrá por ahi otros códigos que pendientes de resolver? Quiero ponerme al dia con el ASM

Nota aclaratoria: el código se ensambla y linkea sin problemas en TASM 5 y TLINK ya que soporta las instrucciones de 386
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar