Les résultats pourraient être un peu trompeur. Quand vous multipliez deux vide matrices, la matrice obtenue est pas immédiatement "alloué" et "initialisé", plutôt c'est reportée jusqu'à la première utilisation (un peu comme une évaluation différée).
La même chose s'applique lorsque l'indexation en dehors des limites pour grandir une variable, qui, dans le cas de tableaux numériques remplit toutes les entrées manquantes avec des zéros (j'en discute ensuite de la non-numérique cas). Bien sûr, la culture de la matrice de cette façon, ne pas remplacer les éléments existants.
Ainsi, alors qu'il peut sembler plus rapide, vous êtes juste de retarder le moment de l'allocation jusqu'à ce que vous en fait de la première utilisation de la matrice. En fin de compte, vous aurez les mêmes périodes que si vous ne l'allocation dès le début.
Exemple pour montrer ce comportement, par rapport à quelques autres alternatives:
N = 1000;
clear z
tic, z = zeros(N,N); toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
clear z
tic, z = zeros(N,0)*zeros(0,N); toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
clear z
tic, z(N,N) = 0; toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
clear z
tic, z = full(spalloc(N,N,0)); toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
clear z
tic, z(1:N,1:N) = 0; toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
clear z
val = 0;
tic, z = val(ones(N)); toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
clear z
tic, z = repmat(0, [N N]); toc
tic, z = z + 1; toc
assert(isequal(z,ones(N)))
Le résultat montre que si l'on somme le temps écoulé pour les deux instructions dans chaque cas, vous vous retrouvez avec total semblable horaires:
// zeros(N,N)
Elapsed time is 0.004525 seconds.
Elapsed time is 0.000792 seconds.
// zeros(N,0)*zeros(0,N)
Elapsed time is 0.000052 seconds.
Elapsed time is 0.004365 seconds.
// z(N,N) = 0
Elapsed time is 0.000053 seconds.
Elapsed time is 0.004119 seconds.
Les autres timings étaient:
// full(spalloc(N,N,0))
Elapsed time is 0.001463 seconds.
Elapsed time is 0.003751 seconds.
// z(1:N,1:N) = 0
Elapsed time is 0.006820 seconds.
Elapsed time is 0.000647 seconds.
// val(ones(N))
Elapsed time is 0.034880 seconds.
Elapsed time is 0.000911 seconds.
// repmat(0, [N N])
Elapsed time is 0.001320 seconds.
Elapsed time is 0.003749 seconds.
Ces mesures sont trop faibles dans les millisecondes et pourraient ne pas être très précis, de sorte que vous pourriez voulez exécuter ces commandes dans une boucle de quelques milliers de fois et en faire la moyenne. Aussi parfois en cours d'exécution enregistrés M-fonctions est plus rapide que l'exécution de scripts ou sur l'invite de commande, comme certaines optimisations seulement se produire de cette façon...
De toute façon l'allocation se fait généralement une fois, alors, qui se soucie si il faut un supplément de 30ms :)
Un comportement similaire peut être observée avec les cellules des tableaux ou des tableaux de structures. Considérons l'exemple suivant:
N = 1000;
tic, a = cell(N,N); toc
tic, b = repmat({[]}, [N,N]); toc
tic, c{N,N} = []; toc
ce qui donne:
Elapsed time is 0.001245 seconds.
Elapsed time is 0.040698 seconds.
Elapsed time is 0.004846 seconds.
Notez que même si ils sont tous égaux, ils occupent des différents quantité de mémoire:
>> assert(isequal(a,b,c))
>> whos a b c
Name Size Bytes Class Attributes
a 1000x1000 8000000 cell
b 1000x1000 112000000 cell
c 1000x1000 8000104 cell
En fait, la situation est un peu plus compliqué ici, depuis MATLAB est probablement le partage de la même matrice vide pour toutes les cellules, plutôt que de créer plusieurs copies.
La matrice de cellules de a
est en fait un tableau de cellules non initialisée (un tableau de pointeurs NULL), tandis que l' b
est une cellule de tableau, où chaque cellule est un tableau vide, []
(en interne et en raison du partage des données, seule la première cellule b{1}
points de []
alors que tous les autres ont une référence à la première cellule). Le tableau final c
est similaire à l' a
(non initialisée cellules), mais avec le dernier contenant un vide numérique de la matrice []
.
J'ai regardé autour de la liste des fonctions C exportées à partir de l' libmx.dll
(à l'aide de Dependency Walker outil), et j'ai trouvé quelques petites choses intéressantes.
il y a des sans-papiers, des fonctions pour la création non initialisée tableaux: mxCreateUninitDoubleMatrix
, mxCreateUninitNumericArray
, et mxCreateUninitNumericMatrix
. Il y a en fait une présentation sur le Fichier d'Échange permet l'utilisation de ces fonctions afin de fournir une alternative plus rapide à l' zeros
fonction.
il existe un sans-papiers fonction appelée mxFastZeros
. Googler en ligne, je peux vous voir de la croix-posté cette question sur MATLAB Réponses ainsi, avec d'excellentes réponses là-bas. James Tursa (même auteur de UNINIT d'avant) a donné un exemple sur la façon d'utiliser ce sans-papiers de fonction.
libmx.dll
est liée à l'encontre tbbmalloc.dll
bibliothèque partagée. C'est Intel TBB évolutive allocateur de mémoire. Cette bibliothèque fournit l'équivalent fonctions d'allocation de mémoire (malloc
, calloc
, free
) optimisé pour les applications parallèles. Rappelez-vous que de nombreuses fonctions MATLAB sont automatiquement multithread, donc je ne serais pas surpris si zeros(..)
est multithread et est à l'aide d'Intel allocateur de mémoire une fois la matrice de taille est assez grande (ici est récent commentaire par Loren Shure qui confirme cet état de fait).
Concernant le dernier point sur l'allocateur de mémoire, vous pouvez écrire une semblable référence en C/C++ similaire à ce que @PavanYalamanchili n', et de comparer les diverses allocateurs disponibles. Quelque chose comme cela. Rappelez-vous que le MEX-files ont un peu plus de la mémoire la gestion des frais généraux, depuis MATLAB libère automatiquement la mémoire qui a été allouée à MEX-files à l'aide de l' mxCalloc
, mxMalloc
ou mxRealloc
fonctions. Pour ce que ça vaut, il était possible de changer de l'intérieur gestionnaire de mémoire dans les anciennes versions.
EDIT:
Ici est un plus approfondie de référence pour comparer l'examen des solutions de rechange. Il montre en particulier que, une fois que vous insistez sur l'utilisation de l'ensemble de l'alloué de la matrice, les trois méthodes sont sur un pied d'égalité, et la différence est négligeable.
function compare_zeros_init()
iter = 100;
for N = 512.*(1:8)
% ZEROS(N,N)
t = zeros(iter,3);
for i=1:iter
clear z
tic, z = zeros(N,N); t(i,1) = toc;
tic, z(:) = 9; t(i,2) = toc;
tic, z = z + 1; t(i,3) = toc;
end
fprintf('N = %4d, ZEROS = %.9f\n', N, mean(sum(t,2)))
% z(N,N)=0
t = zeros(iter,3);
for i=1:iter
clear z
tic, z(N,N) = 0; t(i,1) = toc;
tic, z(:) = 9; t(i,2) = toc;
tic, z = z + 1; t(i,3) = toc;
end
fprintf('N = %4d, GROW = %.9f\n', N, mean(sum(t,2)))
% ZEROS(N,0)*ZEROS(0,N)
t = zeros(iter,3);
for i=1:iter
clear z
tic, z = zeros(N,0)*zeros(0,N); t(i,1) = toc;
tic, z(:) = 9; t(i,2) = toc;
tic, z = z + 1; t(i,3) = toc;
end
fprintf('N = %4d, MULT = %.9f\n\n', N, mean(sum(t,2)))
end
end
Ci-dessous sont les horaires en moyenne plus de 100 itérations en termes d'augmentation de la taille de la matrice. J'ai effectué les tests en R2013a.
>> compare_zeros_init
N = 512, ZEROS = 0.001560168
N = 512, GROW = 0.001479991
N = 512, MULT = 0.001457031
N = 1024, ZEROS = 0.005744873
N = 1024, GROW = 0.005352638
N = 1024, MULT = 0.005359236
N = 1536, ZEROS = 0.011950846
N = 1536, GROW = 0.009051589
N = 1536, MULT = 0.008418878
N = 2048, ZEROS = 0.012154002
N = 2048, GROW = 0.010996315
N = 2048, MULT = 0.011002169
N = 2560, ZEROS = 0.017940950
N = 2560, GROW = 0.017641046
N = 2560, MULT = 0.017640323
N = 3072, ZEROS = 0.025657999
N = 3072, GROW = 0.025836506
N = 3072, MULT = 0.051533432
N = 3584, ZEROS = 0.074739924
N = 3584, GROW = 0.070486857
N = 3584, MULT = 0.072822335
N = 4096, ZEROS = 0.098791732
N = 4096, GROW = 0.095849788
N = 4096, MULT = 0.102148452