Este fin de semana, Guti me envió una captura del programa Derive 6 (programa para cálculo matemático, estilo Matlab).
En la captura me enseñaba como el programa multiplicaba dos matrices cuadradas de 200×200 en unos 4 segundos. Me creo que tiene un K7 a 2.4Ghz.
Curiosamente por casualidades de la vida, no hace muchos dias, he tenido que implementar una función en C para realizar el productos vectorial de 2 matrices….. Y me puse a comparar tiempos…
En mi portatil clónico P4 a 1.8Ghz con 512kb cache y multiplicando dos matrices de 200×200 de floats…….. 0.17 segundos!!!.
No está mal, y eso que está en C sin utilizar ensamblador, por lo que me temo que aún se puede «tunear» bastante más.
Aquí os pongo el código de la función por si a alguien le puede ser útil.
La función recibe los siguientes parametros:
src1 -> puntero a la primera matrix
xsrc1 -> ancho primera matrix
ysrc1 -> alto primera matrix
src2 -> puntero a la segunda matrix
xsrc2 -> ancho segunda matrix
ysrc2 -> alto segunda matrix
dst -> matriz destino
xdst -> ancho matrix destino
ydst ->alto matrix destino
La función presupone que las matrices se puede multiplicar y que los punteros están reservados correctamente…. que sus aproveche.
void ProductoVectorialNxN(float *src1, int xsrc1, int ysrc1, float *src2, int xsrc2, int ysrc2, float *dst, int *xdst, int *ydst)
{
float *Srca, *Srcb;
float value;
*xdst = xsrc2;
*ydst = ysrc1;
for(int n0=0; n0<ysrc1; n0++)
{
for(int n1=0; n1<xsrc2; n1++)
{
Srca = src1 + (n0*this->m_iWidth*sizeof(float));
Srcb = src2 + (n1*sizeof(DTYPE));
value = 0;
for(int n2=xsrc1; n2>0; n2–)
{
value+= *(Srca++) * *(Srcb);
Srcb+= xsrc2*sizeof(float);
}
*(Dst++) = value;
}
}
}
6 Comments
-
Probablemente el algoritmo de multiplicación de Derive esté más optimizado para casos partículares concretos, en función de las características concretas de cada matriz, pero realizar los cálculos con precisión arbitraria y no con floats, le resta eficiencia.
Por otro lado, al menos las versiones iniciales de Derive estaban escritas en Lisp, no es posible mejorar el rendimiento de C con Lisp. En un caso ideal se podría igualar, pero nada más.
Respecto a que C no es un buen lenguaje para manejar recursos, permíteme dudarlo… Solamente ensamblador se me antoja mejor, y en casos puntuales en los que se genera código para una única arquitectura concreta.
-
Este código, creo que tiene algunos problemas de overruns.
Al menos con mi VC++ los daba. Recorres todo con punteros, y los incrementas en sizeof(float) unidades, pero date cuenta que si incrementas un puntero, ya aumenta en los bytes ocupados por el tipo base, con lo que al final acceden a posiciones no reservadas.Aquí va la versión que creo que está corregida (no me he parado a mirar si el resultado es correcto):
void MatMul2 (float *src1, unsigned int xsrc1, unsigned int ysrc1, float *src2, unsigned int xsrc2, unsigned int ysrc2, float *dst, unsigned int *xdst, unsigned int *ydst)
{
unsigned int n0, n1, n2;
float *Srca, *Srcb;
float value;*xdst = xsrc2;
*ydst = ysrc1;for (n0=0; n0<ysrc1; n0++)
{
Srca = src1 + n0;
for (n1=0; n1<xsrc2; n1++)
{
Srcb = src2 + n1;
value = 0;
for (int n2=xsrc1; n2>0; n2–)
{
value+= *(Srca++) * *(Srcb);
Srcb+= xsrc2;
}
*(dst++) = value;
}
}
} -
Una multiplicación de 500×500 ha tardado 1468 ms.
El ejemplo completo:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>void MatMul (float *src1, unsigned int xsrc1, unsigned int ysrc1, float *src2, unsigned int xsrc2, unsigned int ysrc2, float *dst, unsigned int *xdst, unsigned int *ydst);
int _tmain(int argc, _TCHAR* argv[])
{
#define SIZE 500
unsigned int i;
unsigned int iXSize, iYSize;
clock_t iStart, iStop;
float *afMatA, *afMatB, *afMatC;afMatA=(float *) new float[SIZE][SIZE];
afMatB=(float *) new float[SIZE][SIZE];
afMatC=(float *) new float[SIZE][SIZE];memset(afMatA, 0, SIZE*SIZE*sizeof(float));
memset(afMatB, 0, SIZE*SIZE*sizeof(float));
memset(afMatC, 0, SIZE*SIZE*sizeof(float));iStart=clock();
MatMul ((float *)afMatA, SIZE, SIZE, (float *)afMatB, SIZE, SIZE, (float *)afMatC, &iXSize, &iYSize);
iStop=clock();
printf("MatMul: %d
", iStop-iStart);delete[] afMatA;
delete[] afMatB;
delete[] afMatC;getchar();
return(0);
}void MatMul (float *src1, unsigned int xsrc1, unsigned int ysrc1, float *src2, unsigned int xsrc2, unsigned int ysrc2, float *dst, unsigned int *xdst, unsigned int *ydst)
{
unsigned int n0, n1, n2;
float *Srca, *Srcb;
float value;*xdst = xsrc2;
*ydst = ysrc1;for (n0=0; n0<ysrc1; n0++)
{
Srca = src1 + n0;
for (n1=0; n1<xsrc2; n1++)
{
Srcb = src2 + n1;
value = 0;
for (int n2=xsrc1; n2>0; n2–)
{
value+= *(Srca++) * *(Srcb);
Srcb+= xsrc2;
}
*(dst++) = value;
}
}
} -
Jeje, al final todo acaba siendo esto:
; — Machine type PW
; mark_description "Intel(R) C++ Compiler for 32-bit applications, Version 9.0 Build 20050430Z %s";
; mark_description "-Qvc7.1 -Qlocation,link,C:\Archivos de programa\Microsoft Visual Studio .NET 2003\Vc7\Bin -c -O2 -Og -Ob";
; mark_description "2 -Oi -Ot -Oy -GT -G7 -GA -D WIN32 -D NDEBUG -D _CONSOLE -D _MBCS -FD -EHs -EHc -ML -Zp16 -Gy -arch:SSE -YuS";
; mark_description "tdAfx.h -FpRelease/MatX.pch -FAs -FaRelease/ -FoRelease/ -W3 -nologo -Zi -Gd -QxK -Qparallel -Qmultibyte-cha";
; mark_description "rs -Qvc7.1 -Qlocation,link,C:\Archivos de programa\Microsoft Visual Studio .NET 2003\Vc7\bin";
;ident "Intel(R) C++ Compiler for 32-bit applications, Version 9.0 Build 20050430Z %s"
;ident "-Qvc7.1 -Qlocation,link,C:\Archivos de programa\Microsoft Visual Studio .NET 2003\Vc7\Bin -c -O2 -Og -Ob2 -Oi -Ot -Oy -GT "
.686P
.387
OPTION DOTNAME
ASSUME CS:FLAT,DS:FLAT,SS:FLAT
;ident "-defaultlib:libcp"
_TEXT SEGMENT DWORD PUBLIC FLAT 'CODE'
; COMDAT _main
; — Begin _main
; mark_begin;
IF @Version GE 612
.MMX
MMWORD TEXTEQU <QWORD>
ENDIF
IF @Version GE 614
.XMM
XMMWORD TEXTEQU <OWORD>
ENDIF
ALIGN 4
PUBLIC _main_main PROC NEAR
; parameter 1(argc): 8 + ebp
; parameter 2(argv): 12 + ebp
$B1$1: ; Preds $B1$0
$LN1:;;; {
push ebp ;12.1
mov ebp, esp ;12.1
sub esp, 3 ;12.1
and esp, -8 ;12.1
add esp, 4 ;12.1
push edi ;12.1
push esi ;12.1
push ebx ;12.1
sub esp, 20 ;12.1
call ___intel_proc_init ;12.1
; LOE
$B1$25: ; Preds $B1$1
stmxcsr DWORD PTR [esp] ;12.1
or DWORD PTR [esp], 32768 ;12.1
ldmxcsr DWORD PTR [esp] ;12.1
$LN2:;;; #define SIZE 500
;;; unsigned int i;
;;; unsigned int iXSize, iYSize;
;;; clock_t iStart, iStop;
;;; float *afMatA, *afMatB, *afMatC;
;;;
;;; afMatA=(float *) new float[SIZE][SIZE];push 1000000 ;19.40
call ??_U@YAPAXI@Z ;19.40
; LOE eax
$B1$26: ; Preds $B1$25
mov edi, eax ;19.40
; LOE edi
$B1$2: ; Preds $B1$26
$LN3:;;; afMatB=(float *) new float[SIZE][SIZE];
push 1000000 ;20.40
call ??_U@YAPAXI@Z ;20.40
; LOE eax edi
$B1$27: ; Preds $B1$2
mov esi, eax ;20.40
; LOE esi edi
$B1$3: ; Preds $B1$27
$LN4:;;; afMatC=(float *) new float[SIZE][SIZE];
push 1000000 ;21.40
call ??_U@YAPAXI@Z ;21.40
; LOE eax esi edi
$B1$28: ; Preds $B1$3
mov ebx, eax ;21.40
; LOE ebx esi edi
$B1$4: ; Preds $B1$28
$LN5:;;;
;;; memset(afMatA, 0, SIZE*SIZE*sizeof(float));push 1000000 ;23.20
push 0 ;23.20
push edi ;23.20
$LN6:
call ___intel_VEC_memzero ;23.2
; LOE ebx esi edi
$B1$5: ; Preds $B1$4
$LN7:;;; memset(afMatB, 0, SIZE*SIZE*sizeof(float));
push 1000000 ;24.20
push 0 ;24.20
push esi ;24.20
$LN8:
call ___intel_VEC_memzero ;24.2
; LOE ebx esi edi
$B1$6: ; Preds $B1$5
$LN9:;;; memset(afMatC, 0, SIZE*SIZE*sizeof(float));
push 1000000 ;25.20
push 0 ;25.20
push ebx ;25.20
$LN10:
call ___intel_VEC_memzero ;25.2
; LOE ebx esi edi
$B1$29: ; Preds $B1$6
add esp, 48 ;25.2
; LOE ebx esi edi
$B1$7: ; Preds $B1$29
$LN11:;;;
;;; iStart=clock();call _clock ;27.9
; LOE eax ebx esi edi
$B1$30: ; Preds $B1$7
mov DWORD PTR [esp+4], eax ;27.9
; LOE ebx esi edi
$B1$8: ; Preds $B1$30
$LN12:;;; MatMul ((float *)afMatA, SIZE, SIZE, (float *)afMatB, SIZE, SIZE, (float *)afMatC, &iXSize, &iYSize);
mov DWORD PTR [esp+8], ebx ;28.2
$LN13:
mov ecx, ebx ;21.40
$LN14:
xor edx, edx ;28.2
; LOE edx ecx esi edi
$B1$9: ; Preds $B1$13 $B1$8
mov DWORD PTR [esp+16], edx ;28.2
mov DWORD PTR [esp+12], edi ;28.2
lea eax, DWORD PTR [edi+edx] ;28.2
xor ebx, ebx ;28.2
; LOE eax ecx ebx esi
$B1$10: ; Preds $B1$12 $B1$9
movss xmm0, DWORD PTR _2il0floatpacket$1 ;28.2
lea edi, DWORD PTR [esi+ebx] ;28.2
mov edx, 500 ;28.2
ALIGN 4
; LOE eax edx ecx ebx esi edi xmm0
$B1$11: ; Preds $B1$11 $B1$10
movss xmm1, DWORD PTR [eax] ;28.2
mulss xmm1, DWORD PTR [edi] ;28.2
add edi, 2000 ;28.2
add eax, 4 ;28.2
addss xmm0, xmm1 ;28.2
add edx, -1 ;28.2
test edx, edx ;28.2
jg $B1$11 ; Prob 97% ;28.2
; LOE eax edx ecx ebx esi edi xmm0
$B1$12: ; Preds $B1$11
movss DWORD PTR [ecx], xmm0 ;28.2
add ebx, 4 ;28.2
add ecx, 4 ;28.2
cmp ebx, 2000 ;28.2
jb $B1$10 ; Prob 97% ;28.2
; LOE eax ecx ebx esi
$B1$13: ; Preds $B1$12
mov edx, DWORD PTR [esp+16] ;
mov edi, DWORD PTR [esp+12] ;
add edx, 4 ;28.2
cmp edx, 2000 ;28.2
jb $B1$9 ; Prob 90% ;28.2
; LOE edx ecx esi edi
$B1$14: ; Preds $B1$13
mov ebx, DWORD PTR [esp+8] ;
$LN15:;;; iStop=clock();
call _clock ;29.8
; LOE eax ebx esi edi bl bh
$B1$15: ; Preds $B1$14
sub eax, DWORD PTR [esp+4] ;29.8
push eax ;29.8
push OFFSET FLAT: ??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@ ;29.8
$LN16:;;; printf("MatMul: %d
", iStop-iStart);call _printf ;30.2
; LOE ebx esi edi bl bh
$B1$16: ; Preds $B1$15
$LN17:
push edi ;19.40
$LN18:;;;
;;; delete[] afMatA;call ??_V@YAXPAX@Z ;32.11
; LOE ebx esi bl bh
$B1$17: ; Preds $B1$16
$LN19:
push esi ;20.40
$LN20:;;; delete[] afMatB;
call ??_V@YAXPAX@Z ;33.11
; LOE ebx bl bh
$B1$18: ; Preds $B1$17
$LN21:
push ebx ;21.40
$LN22:;;; delete[] afMatC;
call ??_V@YAXPAX@Z ;34.11
; LOE
$B1$32: ; Preds $B1$18
add esp, 20 ;34.11
; LOE
$B1$19: ; Preds $B1$32
$LN23:;;;
;;; getchar();mov eax, DWORD PTR __iob+4 ;36.2
add eax, -1 ;36.2
mov DWORD PTR __iob+4, eax ;36.2
test eax, eax ;36.2
jl $B1$22 ; Prob 1% ;36.2
; LOE
$B1$20: ; Preds $B1$19
add DWORD PTR __iob, 1 ;36.2
; LOE
$B1$21: ; Preds $B1$33 $B1$20
$LN24:;;; return(0);
xor eax, eax ;37.8
add esp, 20 ;37.8
pop ebx ;37.8
pop esi ;37.8
pop edi ;37.8
mov esp, ebp ;37.8
pop ebp ;37.8
ret ;37.8
; LOE
$B1$22: ; Preds $B1$19 ; Infreq
$LN25:
push OFFSET FLAT: __iob ;36.2
call __filbuf ;36.2
; LOE
$B1$33: ; Preds $B1$22 ; Infreq
pop ecx ;36.2
jmp $B1$21 ; Prob 100% ;36.2
ALIGN 4
; LOE
; mark_end;
_main ENDP
.LN_main:
;_main ENDS
_TEXT ENDS
_DATA SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA ENDS
; — End _main
_TEXT SEGMENT DWORD PUBLIC FLAT 'CODE'
; COMDAT ?MatMul@@YAXPAMII0II0PAI1@Z
; — Begin ?MatMul@@YAXPAMII0II0PAI1@Z
; mark_begin;
ALIGN 4
PUBLIC ?MatMul@@YAXPAMII0II0PAI1@Z?MatMul@@YAXPAMII0II0PAI1@Z PROC NEAR
; parameter 1(src1): 32 + esp
; parameter 2(xsrc1): 36 + esp
; parameter 3(ysrc1): 40 + esp
; parameter 4(src2): 44 + esp
; parameter 5(xsrc2): 48 + esp
; parameter 6(ysrc2): 52 + esp
; parameter 7(dst): 56 + esp
; parameter 8(xdst): 60 + esp
; parameter 9(ydst): 64 + esp
$B2$1: ; Preds $B2$0;;; {
$LN26:
push edi ;42.1
push esi ;42.1
push ebp ;42.1
push ebx ;42.1
sub esp, 12 ;42.1
$LN27:
mov ebp, DWORD PTR [esp+36] ;41.6
mov ecx, DWORD PTR [esp+40] ;41.6
mov edx, DWORD PTR [esp+48] ;41.6
mov eax, DWORD PTR [esp+56] ;41.6
mov edi, DWORD PTR [esp+64] ;41.6
mov DWORD PTR [esp+4], eax ;41.6
$LN28:;;; unsigned int n0, n1, n2;
;;; float *Srca, *Srcb;
;;; float value;
;;;
;;; *xdst = xsrc2;
;;; *ydst = ysrc1;
;;;
;;; for (n0=0; n0<ysrc1; n0++)test ecx, ecx ;50.2
$LN29:
mov eax, DWORD PTR [esp+60] ;41.6
$LN30:
mov DWORD PTR [eax], edx ;47.2
$LN31:
mov DWORD PTR [edi], ecx ;48.2
$LN32:
jbe $B2$12 ; Prob 2% ;50.2
; LOE edx ecx ebx ebp esi
$B2$2: ; Preds $B2$1
xor eax, eax ;
; LOE eax edx ecx ebp
$B2$3: ; Preds $B2$13 $B2$10 $B2$2
$LN33:;;; {
;;; Srca = src1 + n0;lea edi, DWORD PTR [eax+eax] ;52.10
add edi, edi ;52.10
add edi, DWORD PTR [esp+32] ;52.10
$LN34:;;; for (n1=0; n1<xsrc2; n1++)
test edx, edx ;53.3
jbe $B2$13 ; Prob 2% ;53.3
; LOE eax edx ecx edi
$B2$4: ; Preds $B2$3
$LN35:;;; {
;;; Srcb = src2 + n1;
;;; value = 0;movss xmm0, DWORD PTR _2il0floatpacket$2 ;56.4
$LN36:;;; for (int n2=xsrc1; n2>0; n2–)
;;; {
;;; value+= *(Srca++) * *(Srcb);
;;; Srcb+= xsrc2;mov ecx, DWORD PTR [esp+4] ;60.5
mov DWORD PTR [esp+8], edi ;60.5
mov edi, DWORD PTR [esp+36] ;60.5
mov DWORD PTR [esp], eax ;60.5
lea esi, DWORD PTR [edx+edx] ;60.5
add esi, esi ;60.5
xor ebp, ebp ;60.5
lea ebx, DWORD PTR [edx+edx] ;60.5
add ebx, ebx ;60.5
; LOE edx ecx ebx ebp esi edi xmm0
$B2$5: ; Preds $B2$9 $B2$4
$LN37:
movaps xmm1, xmm0 ;56.4
$LN38:
mov edx, ebp ;55.11
add edx, DWORD PTR [esp+44] ;55.11
$LN39:
mov eax, edi ;42.1
$LN40:
test edi, edi ;57.4
jle $B2$9 ; Prob 2% ;57.4
; LOE eax edx ecx ebx ebp esi edi xmm0 xmm1
$B2$6: ; Preds $B2$5
mov edi, DWORD PTR [esp+8] ;
ALIGN 4
; LOE eax edx ecx ebx ebp esi edi xmm0 xmm1
$B2$7: ; Preds $B2$7 $B2$6
$LN41:
movss xmm2, DWORD PTR [edi] ;59.15
$LN42:
mulss xmm2, DWORD PTR [edx] ;59.27
$LN43:
add edx, esi ;60.5
$LN44:
add eax, -1 ;57.29
$LN45:
addss xmm1, xmm2 ;59.5
$LN46:
add edi, 4 ;59.15
$LN47:
test eax, eax ;57.4
jg $B2$7 ; Prob 97% ;57.4
; LOE eax edx ecx ebx ebp esi edi xmm0 xmm1
$B2$8: ; Preds $B2$7
mov DWORD PTR [esp+8], edi ;
mov edi, DWORD PTR [esp+36] ;
; LOE ecx ebx ebp esi edi xmm0 xmm1
$B2$9: ; Preds $B2$8 $B2$5
$LN48:;;; }
;;; *(dst++) = value;movss DWORD PTR [ecx], xmm1 ;62.6
$LN49:
add ebp, 4 ;53.24
$LN50:
add ecx, 4 ;62.6
$LN51:
cmp ebp, ebx ;53.3
jb $B2$5 ; Prob 97% ;53.3
; LOE ecx ebx ebp esi edi xmm0
$B2$10: ; Preds $B2$9
mov eax, DWORD PTR [esp] ;
mov edx, DWORD PTR [esp+48] ;
mov DWORD PTR [esp+4], ecx ;
mov ecx, DWORD PTR [esp+40] ;
$LN52:
add eax, 1 ;50.23
$LN53:
cmp eax, ecx ;50.2
jb $B2$3 ; Prob 90% ;50.2
; LOE eax edx ecx
$B2$12: ; Preds $B2$13 $B2$10 $B2$1 ; Infreq
$LN54:;;; }
;;; }
;;; }add esp, 12 ;65.1
pop ebx ;65.1
pop ebp ;65.1
pop esi ;65.1
pop edi ;65.1
ret ;65.1
; LOE
$B2$13: ; Preds $B2$3 ; Infreq
$LN55:
add eax, 1 ;50.23
$LN56:
cmp eax, ecx ;50.2
jb $B2$3 ; Prob 90% ;50.2
jmp $B2$12 ; Prob 100% ;50.2
ALIGN 4
ALIGN 4
; LOE eax edx ecx
; mark_end;
?MatMul@@YAXPAMII0II0PAI1@Z ENDP
.LN?MatMul@@YAXPAMII0II0PAI1@Z:
;?MatMul@@YAXPAMII0II0PAI1@Z ENDS
_TEXT ENDS
_DATA SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA ENDS
; — End ?MatMul@@YAXPAMII0II0PAI1@Z
_RDATA SEGMENT DWORD PUBLIC FLAT 'DATA'
_2il0floatpacket$1 DD 000000000H
_2il0floatpacket$2 DD 000000000H
_RDATA ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?all@?$_Locbase@H@std@@2HB
;?all@?$_Locbase@H@std@@2HB ENDS
_DATA1 ENDS
; COMDAT ?all@?$_Locbase@H@std@@2HB
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?all@?$_Locbase@H@std@@2HB
?all@?$_Locbase@H@std@@2HB DD 63
;?all@?$_Locbase@H@std@@2HB ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?skipws@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?skipws@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?skipws@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?skipws@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?skipws@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 1
;?skipws@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?unitbuf@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?unitbuf@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?unitbuf@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?unitbuf@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?unitbuf@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 2
;?unitbuf@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?uppercase@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?uppercase@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?uppercase@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?uppercase@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?uppercase@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 4
;?uppercase@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?showbase@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?showbase@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?showbase@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?showbase@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?showbase@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 8
;?showbase@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?showpoint@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?showpoint@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?showpoint@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?showpoint@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?showpoint@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 16
;?showpoint@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?showpos@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?showpos@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?showpos@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?showpos@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?showpos@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 32
;?showpos@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?left@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?left@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?left@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?left@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?left@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 64
;?left@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?right@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?right@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?right@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?right@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?right@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 128
;?right@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?internal@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?internal@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?internal@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?internal@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?internal@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 256
;?internal@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?dec@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?dec@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?dec@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?dec@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?dec@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 512
;?dec@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?oct@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?oct@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?oct@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?oct@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?oct@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 1024
;?oct@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?hex@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?hex@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?hex@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?hex@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?hex@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 2048
;?hex@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?scientific@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?scientific@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?scientific@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?scientific@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?scientific@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 4096
;?scientific@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?fixed@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?fixed@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?fixed@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?fixed@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?fixed@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 8192
;?fixed@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?boolalpha@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?boolalpha@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?boolalpha@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?boolalpha@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?boolalpha@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 16384
;?boolalpha@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?adjustfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?adjustfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?adjustfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?adjustfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?adjustfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 448
;?adjustfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?basefield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?basefield@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?basefield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?basefield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?basefield@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 3584
;?basefield@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?floatfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
;?floatfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
; COMDAT ?floatfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?floatfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B
?floatfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B DD 12288
;?floatfield@?$_Iosb@H@std@@2W4_Fmtflags@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?goodbit@?$_Iosb@H@std@@2W4_Iostate@12@B
;?goodbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
; COMDAT ?goodbit@?$_Iosb@H@std@@2W4_Iostate@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?goodbit@?$_Iosb@H@std@@2W4_Iostate@12@B
?goodbit@?$_Iosb@H@std@@2W4_Iostate@12@B DD 0
;?goodbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?eofbit@?$_Iosb@H@std@@2W4_Iostate@12@B
;?eofbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
; COMDAT ?eofbit@?$_Iosb@H@std@@2W4_Iostate@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?eofbit@?$_Iosb@H@std@@2W4_Iostate@12@B
?eofbit@?$_Iosb@H@std@@2W4_Iostate@12@B DD 1
;?eofbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?failbit@?$_Iosb@H@std@@2W4_Iostate@12@B
;?failbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
; COMDAT ?failbit@?$_Iosb@H@std@@2W4_Iostate@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?failbit@?$_Iosb@H@std@@2W4_Iostate@12@B
?failbit@?$_Iosb@H@std@@2W4_Iostate@12@B DD 2
;?failbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?badbit@?$_Iosb@H@std@@2W4_Iostate@12@B
;?badbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
; COMDAT ?badbit@?$_Iosb@H@std@@2W4_Iostate@12@B
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ?badbit@?$_Iosb@H@std@@2W4_Iostate@12@B
?badbit@?$_Iosb@H@std@@2W4_Iostate@12@B DD 4
;?badbit@?$_Iosb@H@std@@2W4_Iostate@12@B ENDS
_DATA1 ENDS
_RDATA SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@
;??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@ ENDS
_RDATA ENDS
; COMDAT ??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@
_RDATA SEGMENT DWORD PUBLIC FLAT 'DATA'
; COMDAT ??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@
??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@ DB 77
DB 97
DB 116
DB 77
DB 117
DB 108
DB 58
DB 32
DB 37
DB 100
DB 10
DB 0
;??_C@_0M@A@MatMul?3?5?$CFd?6?$AA@ ENDS
_RDATA ENDS
_DATA SEGMENT DWORD PUBLIC FLAT 'DATA'
EXTRN __iob:BYTE
EXTRN __fltused:BYTE
_DATA ENDS
EXTRN ___intel_VEC_memzero:PROC
EXTRN _clock:PROC
EXTRN ??_U@YAPAXI@Z:PROC
EXTRN ??_V@YAXPAX@Z:PROC
EXTRN _printf:PROC
EXTRN __filbuf:PROC
EXTRN ___intel_proc_init:PROC
END -
He estado haciendo algunos retoques sobre tu implementación (el algoritmo es el que es, no creo que haya nada más eficiente), y no he conseguido mejorar tus tiempos.
¡Enhorabuena!
¿¿4 segundos de Derive contra 0.17 segundos de un programa casero en C??
No fucking way.
A menos que hayas querido decir 4 segundos contra 17. En ese caso es más creíble. De todas formas deberías de saber que C hace ciertas optimizaciones a niver compilación por defecto (a menos que se las desactives – opción -O en el gcc ) y el algoritmo que usás de multiplicación de matrices – brute force – tiene un orden polinómico, sino exponencial o factorial. Eso quiere decir que mientras más grande sea la matriz más se va a notar la diferencia entre un algoritmo especializado, optimizado y único como el que seguramente usa derive contra el básico que estás utilizando.
Sería interesante comparar curvas de comportamiento con matrices pequeñas y matrices más grandes (rango 250, 300, 500 y 1000 por ejemplo) para poder ver una muestra cuantitativa.
No quiere decir esto que C no sea buen lenguaje, al contrario, es excelente como lenguaje de uso generalizado. Ni hablar para el manejo de recursos; pero no creo que pueda competir a una escala significativa contra ciertas aplicaciones en su campo.