Por que o MATLAB é tão rápido na multiplicação de matrizes?


190

Estou fazendo alguns benchmarks com CUDA, C ++, C #, Java e usando o MATLAB para verificação e geração de matriz. Quando executo a multiplicação de matrizes com o MATLAB, 2048x2048matrizes ainda maiores são multiplicadas quase instantaneamente.

             1024x1024   2048x2048   4096x4096
             ---------   ---------   ---------
CUDA C (ms)      43.11      391.05     3407.99
C++ (ms)       6137.10    64369.29   551390.93
C# (ms)       10509.00   300684.00  2527250.00
Java (ms)      9149.90    92562.28   838357.94
MATLAB (ms)      75.01      423.10     3133.90

Somente a CUDA é competitiva, mas achei que pelo menos o C ++ seria um pouco próximo e não 60 vezes mais lento. Também não sei o que pensar sobre os resultados do C #. O algoritmo é o mesmo que C ++ e Java, mas há um salto gigante 2048de 1024.

Como o MATLAB está realizando a multiplicação de matrizes tão rápido?

Código C ++:

float temp = 0;
timer.start();
for(int j = 0; j < rozmer; j++)
{
    for (int k = 0; k < rozmer; k++)
    {
        temp = 0;
        for (int m = 0; m < rozmer; m++)
        {
            temp = temp + matice1[j][m] * matice2[m][k];
        }
        matice3[j][k] = temp;
    }
}
timer.stop();

14
Provavelmente é uma questão de qual algoritmo você usa.
Robert J.

24
Certifique-se de que o Matlab não está armazenando em cache o resultado, é um animal complicado. Primeiro, verifique se o cálculo está realmente sendo realizado e depois compare.
Rubenvb 19/05/11


10
Na verdade, acho que este post é realmente interessante, mas eu gostaria de ver benchmarks mais apropriados. Por exemplo, acho que o Matlab R2011a está usando multithreading automaticamente e as multiplicações de matriz são implementadas usando a biblioteca mkl / blas da Intel. Assim, eu acho que o c ++ é mais rápido se alguém usasse uma chamada mkl para fazer a multiplicação da matriz. A questão seria então qual é a sobrecarga do Matlab. Eu sei que isso depende de detalhes adicionais da multiplicação de matrizes, mas os números acima não têm sentido no momento.
Lucas

1
você pode usar o "algoritmo Strassen" do tempo de execução O (n ^ 2,81) para multiplicação de matriz quadrada grande que é cerca de 10x mais rápida que a multiplicação nativa que é executada em O (n ^ 3). também o SSE / AVX pode ajudá-lo a ficar 8 a 20 vezes mais rápido para a execução do código. todos juntos, você pode ter uma implementação de CA mais rápida que a do matlab.
DU Jiaen

Respostas:


85

Aqui estão meus resultados usando a Caixa de ferramentas de computação paralela MATLAB R2011a + em uma máquina com um Tesla C2070:

>> A = rand(1024); gA = gpuArray(A);
% warm up by executing the operations a couple of times, and then:
>> tic, C = A * A; toc
Elapsed time is 0.075396 seconds.
>> tic, gC = gA * gA; toc
Elapsed time is 0.008621 seconds.

O MATLAB usa bibliotecas altamente otimizadas para multiplicação de matrizes, e é por isso que a multiplicação simples de matrizes MATLAB é tão rápida. A gpuArrayversão usa MAGMA .

Atualize usando o R2014a em uma máquina com um Tesla K20c e o novotimeit e gputimeitfunções:

>> A = rand(1024); gA = gpuArray(A);
>> timeit(@()A*A)
ans =
    0.0324
>> gputimeit(@()gA*gA)
ans =
    0.0022

Atualizar usando o R2018b em uma máquina WIN64 com 16 núcleos físicos e um Tesla V100:

>> timeit(@()A*A)
ans =
    0.0229
>> gputimeit(@()gA*gA)
ans =
   4.8019e-04

(Nota: em algum momento (eu esqueço exatamente)) gpuArraydo MAGMA para o cuBLAS - o MAGMA ainda é usado em algumas gpuArrayoperações)


Por que isso importa?
Mad Physicist

Por que o que importa? Eu estava tentando fornecer algumas dicas sobre as bibliotecas usadas pelo MATLAB em várias situações para explicar por que o desempenho do MATLAB é bom - ou seja, porque ele usa bibliotecas numéricas altamente otimizadas.
Edric

175

Esse tipo de pergunta é recorrente e deve ser respondida com mais clareza do que "MATLAB usa bibliotecas altamente otimizadas" ou "MATLAB usa o MKL" pela primeira vez no Stack Overflow.

História:

A multiplicação de matrizes (juntamente com a matriz de vetores, multiplicação de vetores e muitas das decomposições de matrizes) é (são) os problemas mais importantes na álgebra linear. Os engenheiros têm resolvido esses problemas com os computadores desde os primeiros dias.

Não sou especialista em história, mas aparentemente naquela época todo mundo reescreveu sua versão do FORTRAN com loops simples. Alguma padronização surgiu com a identificação de "kernels" (rotinas básicas) que a maioria dos problemas de álgebra linear precisava para ser resolvida. Essas operações básicas foram padronizadas em uma especificação chamada: Subprogramas Básicos de Álgebra Linear (BLAS). Os engenheiros poderiam então chamar essas rotinas BLAS padrão e bem testadas em seu código, facilitando muito o trabalho.

BLAS:

O BLAS evoluiu do nível 1 (a primeira versão que definiu operações de vetor escalar e vetor de vetor) para o nível 2 (operações de matriz vetorial) para o nível 3 (operações de matriz matricial) e forneceu mais e mais "kernels" para padronizar mais e mais das operações fundamentais de álgebra linear. As implementações originais do FORTRAN 77 ainda estão disponíveis no site da Netlib .

Para um melhor desempenho:

Assim, ao longo dos anos (principalmente entre os lançamentos BLAS nível 1 e nível 2: início dos anos 80), o hardware mudou, com o advento das operações de vetor e hierarquias de cache. Essas evoluções permitiram aumentar substancialmente o desempenho das sub-rotinas BLAS. Diferentes fornecedores surgiram com a implementação de rotinas BLAS, cada vez mais eficientes.

Não conheço todas as implementações históricas (eu não nasci ou era criança na época), mas duas das mais notáveis ​​surgiram no início dos anos 2000: o Intel MKL e o GotoBLAS. Seu Matlab usa o Intel MKL, que é um BLAS muito bom e otimizado, o que explica o ótimo desempenho que você vê.

Detalhes técnicos sobre multiplicação de matrizes:

Então, por que o Matlab (o MKL) é tão rápido dgemm(multiplicação matriz-matriz geral de dupla precisão)? Em termos simples: porque usa vetorização e bom cache de dados. Em termos mais complexos: veja o artigo fornecido por Jonathan Moore.

Basicamente, quando você executa sua multiplicação no código C ++ que você forneceu, você não é totalmente compatível com o cache. Como suspeito que você tenha criado uma matriz de ponteiros para matrizes de linha, seus acessos no loop interno à k-ésima coluna de "matice2": matice2[m][k]são muito lentos. De fato, quando você acessa matice2[0][k], você deve obter o k-ésimo elemento da matriz 0 da sua matriz. Na próxima iteração, você deve acessar matice2[1][k], que é o k-ésimo elemento de outra matriz (a matriz 1). Então, na próxima iteração, você acessa outra matriz, e assim por diante ... Como a matriz inteira matice2não pode se encaixar nos caches mais altos (seus 8*1024*1024bytes são grandes), o programa deve buscar o elemento desejado da memória principal, perdendo muito Tempo.

Se você acabou de transpor a matriz, para que os acessos estivessem em endereços de memória contíguos, seu código já seria executado muito mais rápido, porque agora o compilador pode carregar linhas inteiras no cache ao mesmo tempo. Apenas tente esta versão modificada:

timer.start();
float temp = 0;
//transpose matice2
for (int p = 0; p < rozmer; p++)
{
    for (int q = 0; q < rozmer; q++)
    {
        tempmat[p][q] = matice2[q][p];
    }
}
for(int j = 0; j < rozmer; j++)
{
    for (int k = 0; k < rozmer; k++)
    {
        temp = 0;
        for (int m = 0; m < rozmer; m++)
        {
            temp = temp + matice1[j][m] * tempmat[k][m];
        }
        matice3[j][k] = temp;
    }
}
timer.stop();

Assim, você pode ver como a localidade do cache aumentou o desempenho do seu código de maneira bastante substancial. Agora realdgemm implementações exploram isso em um nível muito extenso: elas realizam a multiplicação em blocos da matriz definida pelo tamanho do TLB (tradução ao lado do buffer de tradução, longa história: o que pode ser efetivamente armazenado em cache), para que sejam transmitidos ao processador exatamente a quantidade de dados que pode processar. O outro aspecto é a vetorização, eles usam as instruções vetorizadas do processador para obter o melhor rendimento de instruções, o que você realmente não pode fazer com o código C ++ de plataforma cruzada.

Finalmente, as pessoas que afirmam que é por causa do algoritmo de Strassen ou Coppersmith – Winograd estão erradas, esses dois algoritmos não são implementáveis ​​na prática, devido às considerações de hardware mencionadas acima.


2
Acabei de assistir a um vídeo de Scott Meyers sobre a importância dos tamanhos de cache e ajuste de dados em tamanhos de linha de cache, e os problemas que você pode ter com soluções multiencadeadas que não têm dados compartilhados na fonte, mas acabam com os dados compartilhados no hardware / nível de thread principal: youtu.be/WDIkqP4JbkE
WillC:

40

É por isso . O MATLAB não executa uma multiplicação de matriz ingênua, fazendo um loop sobre cada elemento da maneira que você fez no seu código C ++.

É claro que estou assumindo que você acabou de usar em C=A*Bvez de escrever uma função de multiplicação.


19

O Matlab incorporou o LAPACK há algum tempo, então suponho que a multiplicação da matriz deles use algo pelo menos tão rápido. O código-fonte e a documentação do LAPACK estão prontamente disponíveis.

Você também pode ler o artigo de Goto e Van De Geijn "Anatomia da multiplicação de matrizes de alto desempenho" em http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.1785&rep=rep1&type=pdf


7
O MATLAB usa a Intel MKL Library, que fornece implementação otimizada das rotinas BLAS / LAPACK: stackoverflow.com/a/16723946/97160
Amro:

11

A resposta é que as bibliotecas LAPACK e BLAS tornam o MATLAB incrivelmente rápido nas operações da matriz, e não qualquer código proprietário do pessoal do MATLAB.

Use as bibliotecas LAPACK e / ou BLAS no seu código C ++ para operações de matriz e você deverá obter desempenho semelhante ao MATLAB. Essas bibliotecas devem estar disponíveis gratuitamente em qualquer sistema moderno e as partes foram desenvolvidas ao longo de décadas na academia. Observe que existem várias implementações, incluindo algumas de código fechado, como o Intel MKL .

Uma discussão sobre como o BLAS obtém alto desempenho está disponível aqui.


BTW, é uma dor grave na minha experiência chamar bibliotecas LAPACK diretamente de c (mas vale a pena). Você precisa ler a documentação MUITO com precisão.


8

Ao fazer a multiplicação de matrizes, você usa o método de multiplicação ingênuo, que leva tempo de O(n^3).

Existem algoritmos de multiplicação de matrizes que são necessários O(n^2.4). O que significa que no n=2000seu algoritmo requer ~ 100 vezes mais computação que o melhor algoritmo.
Você deve realmente verificar a página da Wikipedia para obter multiplicação de matrizes para obter mais informações sobre as maneiras eficientes de implementá-la.


e o MATLAB provavelmente usa esse algoritmo, já que o tempo para multiplicar a matriz 1024 * 1024 é menor que 8 vezes o tempo para a multiplicação da matriz 2048 * 2048! Bem feito pessoal do MATLAB.
Renaud

4
Eu duvido que eles usem algoritmos de multiplicação "eficientes", apesar de suas vantagens teóricas. Até o algoritmo de Strassen tem dificuldades de implementação, e o algoritmo Coppersmith – Winograd que você provavelmente leu simplesmente não é prático (agora). Além disso, encadeamento SO relacionado: stackoverflow.com/questions/17716565/…
Ernir

Esse algoritmo é apenas para matrizes extremamente grandes.

@Renaud. Essa é a definição de sobrecarga relativamente constante
Mad Physicist

6

Dependendo da sua versão do Matlab, acredito que ele já esteja usando sua GPU.

Outra coisa; O Matlab mantém o controle de muitas propriedades da sua matriz; se sua diagonal, hermética e assim por diante, e especializa seus algoritmos baseados nela. Talvez seja especializado com base na matriz zero que você está passando, ou algo assim? Talvez seja o cache de chamadas de função repetidas, o que atrapalha o seu tempo? Talvez otimize produtos matriciais não utilizados repetidos?

Para evitar que essas coisas aconteçam, use uma matriz de números aleatórios e certifique-se de forçar a execução imprimindo o resultado na tela ou no disco ou algo assim.


4
Como um usuário pesado de ML, posso dizer que eles ainda não estão usando GPGPU. A nova versão do matlab usa o SSE1 / 2 (finalmente). Mas eu fiz testes. Uma MexFunction executando uma multiplicação por elementos é executada duas vezes mais rápido que A.*Bele. Portanto, o OP está quase certamente brincando com alguma coisa.
KitsuneYMG

6
O Matlab com Parallel Computing Toolbox pode usar uma GPU CUDA, mas é explícito - você precisa enviar os dados para a GPU.
Edric

Eu uso M1 = único (rand (1024.1024) * 255); M2 = simples (margem (1024, 1024) * 255); e M3 = M1 * M2; ... então escreva no arquivo binário de carros alegóricos, tudo feito muito rapidamente.
Lobo

3

O MATLAB usa uma implementação altamente otimizada do LAPACK da Intel, conhecida como Intel Math Kernel Library (Intel MKL) - especificamente a função dgemm . A velocidade Esta biblioteca aproveita os recursos do processador, incluindo instruções SIMD e processadores com vários núcleos. Eles não documentam qual algoritmo específico eles usam. Se você ligar para o Intel MKL a partir do C ++, deverá ter um desempenho semelhante.

Não tenho certeza de qual biblioteca o MATLAB usa para multiplicação de GPU, mas provavelmente algo como nVidia CUBLAS .


1
Você está certo, mas você já viu esta resposta ? No entanto, o IPP não é MKL e o MKL tem um desempenho álgebra linear muito superior ao IPP. Além disso, o IPP reprovou seu módulo de matemática matricial nas versões recentes.
Chappjc 10/09/2015

Desculpe eu quis dizer MKL não IPP
gregswiss

Você está certo, a outra resposta cobre. É tão detalhado que eu perdi.
gregswiss

2

A resposta geral para "Por que o matlab é mais rápido em executar xxx do que outros programas" é que o matlab possui muitas funções otimizadas.

Os outros programas usados ​​frequentemente não possuem essas funções, portanto as pessoas aplicam suas próprias soluções criativas, que são surpreendentemente mais lentas que o código otimizado profissionalmente.

Isso pode ser interpretado de duas maneiras:

1) A maneira comum / teórica: o Matlab não é significativamente mais rápido, você está apenas fazendo o benchmark errado

2) A maneira realista: Para esse material, o Matlab é mais rápido na prática, porque linguagens como c ++ são usadas com muita facilidade de maneiras ineficazes.


7
Ele está comparando a velocidade do MATLAB com a velocidade de uma função que ele escreveu em dois minutos. Posso escrever uma função mais rápida em 10 minutos ou uma função muito mais rápida em duas horas. Os caras do MATLAB passaram mais de duas horas acelerando sua multiplicação de matrizes.
gnasher729

2

O forte contraste não se deve apenas à incrível otimização do Matlab (como já foi discutido por muitas outras respostas), mas também à maneira como você formulou a matriz como um objeto.

Parece que você fez da matriz uma lista de listas? Uma lista de listas contém ponteiros para listas que contêm os elementos da matriz. Os locais das listas contidas são atribuídos arbitrariamente. Como você está repetindo seu primeiro índice (número da linha?), O tempo de acesso à memória é muito significativo. Em comparação, por que você não tenta implementar a matriz como uma única lista / vetor usando o seguinte método?

#include <vector>

struct matrix {
    matrix(int x, int y) : n_row(x), n_col(y), M(x * y) {}
    int n_row;
    int n_col;
    std::vector<double> M;
    double &operator()(int i, int j);
};

E

double &matrix::operator()(int i, int j) {
    return M[n_col * i + j];
}

O mesmo algoritmo de multiplicação deve ser usado para que o número de flop seja o mesmo. (n ^ 3 para matrizes quadradas de tamanho n)

Estou pedindo para cronometrar para que o resultado seja comparável ao que você tinha anteriormente (na mesma máquina). Com a comparação, você mostrará exatamente o quão significativo o tempo de acesso à memória pode ser!


2

É lento no C ++ porque você não está usando multithreading. Essencialmente, se A = BC, onde todas são matrizes, a primeira linha de A pode ser calculada independentemente da 2ª linha, etc. Se A, B e C são todos n por n matrizes, você pode acelerar a multiplicação por um fator de n ^ 2, como

a_ {i, j} = soma_ {k} b_ {i, k} c_ {k, j}

Se você usa, digamos, Eigen [ http://eigen.tuxfamily.org/dox/GettingStarted.html ], o multithreading é incorporado e o número de threads é ajustável.


2

Porque o MATLAB é uma linguagem de programação desenvolvida inicialmente para álgebra linear numérica (manipulação de matrizes), que possui bibliotecas especialmente desenvolvidas para multiplicações de matrizes. E agora o MATLAB também pode usar as GPUs (unidade de processamento gráfico) para isso adicionalmente.

E se olharmos para os seus resultados de computação:

             1024x1024   2048x2048   4096x4096
             ---------   ---------   ---------
CUDA C (ms)      43.11      391.05     3407.99
C++ (ms)       6137.10    64369.29   551390.93
C# (ms)       10509.00   300684.00  2527250.00
Java (ms)      9149.90    92562.28   838357.94
MATLAB (ms)      75.01      423.10     3133.90

então podemos ver que não apenas o MATLAB é tão rápido na multiplicação de matrizes: CUDA C (linguagem de programação da NVIDIA) tem resultados melhores que o MATLAB. O CUDA C também possui bibliotecas especialmente desenvolvidas para multiplicações de matrizes e utiliza as GPUs.

Breve história do MATLAB

Cleve Moler, presidente do departamento de ciência da computação da Universidade do Novo México, começou a desenvolver o MATLAB no final da década de 1970. Ele o projetou para dar a seus alunos acesso ao LINPACK (uma biblioteca de software para a realização de álgebra linear numérica) e EISPACK(é uma biblioteca de software para computação numérica de álgebra linear) sem que eles precisem aprender o Fortran. Logo se espalhou para outras universidades e encontrou um forte público na comunidade de matemática aplicada. Jack Little, um engenheiro, foi exposto a ele durante uma visita que Moler fez à Universidade de Stanford em 1983. Reconhecendo seu potencial comercial, ele se juntou a Moler e Steve Bangert. Eles reescreveram o MATLAB em C e fundaram o MathWorks em 1984 para continuar seu desenvolvimento. Essas bibliotecas reescritas eram conhecidas como JACKPAC. Em 2000, o MATLAB foi reescrito para usar um novo conjunto de bibliotecas para manipulação de matrizes, LAPACK (é uma biblioteca de software padrão para álgebra linear numérica).

Fonte

O que é CUDA C

O CUDA C também usa bibliotecas especialmente desenvolvidas para multiplicações de matrizes como o OpenGL (Open Graphics Library). Ele também usa GPU e Direct3D (no MS Windows).

A plataforma CUDA foi projetada para trabalhar com linguagens de programação como C, C ++ e Fortran. Essa acessibilidade facilita o uso de recursos da GPU por especialistas em programação paralela, ao contrário das APIs anteriores, como Direct3D e OpenGL , que exigiam habilidades avançadas em programação gráfica. Além disso, o CUDA suporta estruturas de programação como o OpenACC e o OpenCL .

insira a descrição da imagem aqui

Exemplo de fluxo de processamento CUDA:

  1. Copiar dados da memória principal para a memória GPU
  2. CPU inicia o kernel de computação da GPU
  3. Os núcleos CUDA da GPU executam o kernel em paralelo
  4. Copie os dados resultantes da memória da GPU para a memória principal

Comparando velocidades de execução de CPU e GPU

Executamos um benchmark no qual medimos o tempo necessário para executar 50 etapas de tempo para tamanhos de grade de 64, 128, 512, 1024 e 2048 em um processador Intel Xeon X5650 e, em seguida, usando uma GPU NVIDIA Tesla C2050.

insira a descrição da imagem aqui

Para um tamanho de grade de 2048, o algoritmo mostra uma redução de 7,5x no tempo de computação de mais de um minuto na CPU para menos de 10 segundos na GPU. O gráfico de escala de log mostra que a CPU é realmente mais rápida para pequenos tamanhos de grade. À medida que a tecnologia evolui e amadurece, no entanto, as soluções de GPU estão cada vez mais capazes de lidar com problemas menores, uma tendência que esperamos continuar.

Fonte

Da introdução ao Guia de programação CUDA C:

Impulsionada pela demanda insaciável do mercado por gráficos 3D de alta definição e em tempo real, a Unidade de Processador Gráfico ou GPU programável evoluiu para um processador manycore altamente paralelo, multithread, com tremenda potência computacional e largura de banda de memória muito alta, conforme ilustrado por Figure 1e Figure 2.

Figura 1. Operações de ponto flutuante por segundo para CPU e GPU

insira a descrição da imagem aqui

Figura 2 . Largura de banda de memória para CPU e GPU

insira a descrição da imagem aqui

A razão por trás da discrepância na capacidade de ponto flutuante entre a CPU e a GPU é que a GPU é especializada em computação altamente paralela, com uso intensivo de computação - exatamente do que trata a renderização gráfica - e, portanto, projetada para que mais transistores sejam dedicados ao processamento de dados em vez de armazenamento em cache de dados e controle de fluxo, conforme ilustrado esquematicamente em Figure 3.

Figura 3 . A GPU dedica mais transistores ao processamento de dados

insira a descrição da imagem aqui

Mais especificamente, a GPU é especialmente adequada para resolver problemas que podem ser expressos como cálculos paralelos a dados - o mesmo programa é executado em muitos elementos de dados em paralelo - com alta intensidade aritmética - a proporção de operações aritméticas e operações de memória. Como o mesmo programa é executado para cada elemento de dados, há um requisito menor para um sofisticado controle de fluxo e, como é executado em muitos elementos de dados e possui alta intensidade aritmética, a latência de acesso à memória pode ser ocultada com cálculos em vez de caches de big data .

O processamento paralelo de dados mapeia elementos de dados para encadeamentos de processamento paralelo. Muitos aplicativos que processam grandes conjuntos de dados podem usar um modelo de programação paralela a dados para acelerar os cálculos. Na renderização 3D, grandes conjuntos de pixels e vértices são mapeados para threads paralelos. Da mesma forma, aplicativos de processamento de imagem e mídia, como pós-processamento de imagens renderizadas, codificação e decodificação de vídeo, dimensionamento de imagem, visão estéreo e reconhecimento de padrões, podem mapear blocos e pixels de imagem para segmentos de processamento paralelos. De fato, muitos algoritmos fora do campo de renderização e processamento de imagens são acelerados pelo processamento paralelo de dados, do processamento geral de sinais ou simulação física às finanças computacionais ou biologia computacional.

Fonte

Leitura avançada


Algumas caras interessantes

Eu escrevi a multiplicação da matriz C ++ que é tão rápida quanto a do Matlab, mas foi preciso algum cuidado. (Antes do Matlab estar usando GPUs para isso).

Citação desta resposta .


2
Essa última citação não é "um fato", é um orgulho vazio. Essa pessoa recebeu vários pedidos de código desde que o publicou. Mas nenhum código à vista.
Cris Luengo

1
Sua descrição da rapidez com que você pode fazer cálculos na GPU não aborda a questão. Todos sabemos que 128 pequenos núcleos podem fazer o mesmo trabalho monótono do que dois grandes núcleos. "E agora o MATLAB também pode usar as GPUs (unidade de processamento gráfico) para isso adicionalmente." Sim, mas não por padrão. A multiplicação normal da matriz ainda usa BLAS.
Cris Luengo

@CrisLuengo, OK, não é um fato! Talvez você esteja certo sobre o seu "gabar-se" - não sabemos sobre isso e também não sabemos por que ele não responde. Para o segundo comentário: a descrição dos cálculos na GPU responde à pergunta porque, para multiplicações de matrizes em álgebra linear, ela usa operações de ponto flutuante. Talvez não seja compreensível para todas as pessoas, mas acho que elas precisam entender esse básico. Em outro caso, eles precisam aprender o básico antes de lerem algum artigo sobre matrizes. E se alguém me escrever sobre isso, adicionarei esses detalhes. Obrigado!
Bharata

@CrisLuengo, escrevi a palavra "additionally". Significa: pode ser usado. Isso também significa que a multiplicação normal da matriz ainda usa bibliotecas de software. Você acha que preciso alterar minha postagem para ser mais compreensível? Obrigado por seus comentários!
Bharata
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.