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 Responder

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

    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 Responder

    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 Responder

    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 Responder

    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 Responder

    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!

Leave a Comment Post us a comment!