2010-10-27 5 views
3

Le goulot d'étranglement dans mon programme calcule le signe d'un nombre pour tous les nombres dans un tableau, lorsque la taille du tableau est très grande. Je montre les deux approches que j'ai essayées ci-dessous, toutes deux avec des résultats similaires. J'ai 16GB de RAM, et le tableau occupe ~ 5GB. Le problème que je vois est la fonction de signe prend beaucoup de RAM + mémoire virtuelle. Quelqu'un sait-il un moyen de réduire les besoins en mémoire et accélérer ce processus pour mettre le signe de l'entrée de tableau dans la sortie du tableau (voir ci-dessous)?Matlab: existe-t-il un moyen d'accélérer le calcul du signe d'un nombre?

L'utilisation d'une boucle for avec les commandes if ou switch ne manque pas de mémoire, mais prend une heure pour se terminer (bien trop longtemps).

size = 1e9; % size of large array (just an example, could be larger) 
output = int8(zeros(size,1)-1); % preallocate to -1 
input = single(rand(size,1)); % create random array between 0 and 1 
scalar = single(0.5); % just a scalar number, set to 0.5 (midpoint) for example 

% approach 1 (comment out when using approach 2) 
output = int8(sign(input - scalar)); % this line of code uses a ton of RAM and virtual memory 

% approach 2 
output(input>scalar) = 1;   % this line of code uses a ton of RAM and virtual memory 
output(input==scalar) = 0;   % this line of code uses a ton of RAM and virtual memory 

Merci d'avance pour toute suggestion.

+0

Avez-vous essayé une implémentation C en utilisant un fichier MEX? –

+0

Quelle plage de valeurs attendez-vous dans votre tableau actuel de valeurs à simple précision? – gnovice

+0

N'a pas essayé un fichier MEX. – ggkmath

Répondre

6

Si vous utilisez une boucle, mais passer les données en morceaux, il est presque aussi rapide que la version entièrement vectorisé, mais sans les frais généraux de mémoire:

chunkSize = 1e7; 
for start=1:chunkSize:size 
    stop = min(start+chunkSize, size); 
    output(start:stop) = int8(sign(input(start:stop)-scalar)); 
end 

En outre, votre code d'initialisation est la création de deux des tableaux de précision puis les convertissent en tableaux simples/entiers. Vous pouvez enregistrer une utilisation temporaire de la mémoire (et l'heure) en faisant:

input = rand(size, 1, 'single'); 
output = zeros(size, 1, 'int8') - 1; 
+0

Excellentes suggestions Ray. Votre solution augmente le temps <10% sans utiliser pratiquement de mémoire. Je pense que cela fonctionnera. Impressionnant! Merci beaucoup!!! – ggkmath

+0

Son genre de contre-intuitif, mais à partir de mes résultats expérimentaux, l'augmentation de chunkSize de 1e7 augmente le temps d'exécution, alors que la diminuer accélère le temps d'exécution (j'aurais attendu l'inverse). Toujours fonctionne bien. – ggkmath

+0

Non, la réduction de chunkSize commence trop à augmenter le temps d'exécution. chunkSize ~ 1e6 semble être l'endroit idéal. – ggkmath

1

Il se peut que sign convertisse l'entrée pour doubler par intermittence.

Quoi qu'il en soit, si elle est bien si output est 1 pour le positif et 0 pour négatif ou nul, vous pouvez essayer

siz = 1e9; %# do not use 'size' as a variable, since it's an important function 
input = rand(siz,1,'single'); %# this directly creates a single array 
scalar = single(0.5); 
output = input>scalar; 

EDIT En fait, je vois un court pic dans l'utilisation de la mémoire, même pour cette solution . Peut-être que cela est lié au multithreading? Quoi qu'il en soit, le problème de vitesse vient du fait que vous commencez à paginer, ce qui ralentit tout à un crawl.

+0

Malheureusement, j'ai besoin que le tableau de sortie soit égal à 1 pour indiquer que l'élément d'entrée est positif, -1 pour négatif, et 0 pour les valeurs de sortie exactement égales à 0 (tout comme la fonction 'signe'). – ggkmath

Questions connexes