PRODUCTO DE MATRICES: Ejemplo práctico

4

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

  • Matías
    5 julio, 2005 a las 4:35

    ¿¿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.

  • Guti
    5 julio, 2005 a las 13:42

    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.

  • Guti
    7 julio, 2005 a las 21:17

    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;
    }
    }
    }

  • Guti
    7 julio, 2005 a las 21:24

    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;
    }
    }
    }

  • Guti
    7 julio, 2005 a las 21:27

    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

  • Guti
    7 julio, 2005 a las 21:50

    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!