Matlab: есть ли способ ускорить вычисление знака числа?

Узким местом в моей программе является вычисление знака числа для всех чисел в массиве, когда размер массива очень велик. Ниже я покажу два испробованных мной подхода, оба с одинаковыми результатами. У меня 16 ГБ ОЗУ, а массив занимает ~ 5 ГБ. Проблема, которую я вижу, заключается в том, что функция знака занимает много оперативной памяти + виртуальной памяти. Кто-нибудь знает способ уменьшить требования к памяти и ускорить этот процесс для помещения знака ввода массива в вывод массива (см. Ниже)?

Использование цикла for с командами if или switch не требует нехватки памяти, но занимает час (слишком долго).

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

Спасибо заранее за любые предложения.


person ggkmath    schedule 27.10.2010    source источник
comment
Вы пробовали реализацию C с использованием файла MEX?   -  person André Caron    schedule 28.10.2010
comment
Какой диапазон значений вы ожидаете увидеть в своем фактическом массиве значений с одинарной точностью?   -  person gnovice    schedule 28.10.2010
comment
Диапазон значений будет между +500 и -500, включая 0.   -  person ggkmath    schedule 28.10.2010
comment
Будут ли значения в этом диапазоне целыми или любыми значениями с плавающей запятой?   -  person gnovice    schedule 28.10.2010
comment
любое значение с плавающей запятой. Массив на самом деле является выходом аналого-цифрового преобразователя с осциллографа, нормализованным к единицам вольт. Осциллограф принимает только входы +/- 500 В, но на практике входной массив будет находиться в диапазоне +/- 50 В, все с плавающей запятой (редко целые числа, но это может случиться).   -  person ggkmath    schedule 28.10.2010


Ответы (2)


Если вы используете цикл for, но передаете данные порциями, это почти так же быстро, как и полностью векторизованная версия, но без накладных расходов на память:

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

Кроме того, ваш код инициализации создает массивы с двойной точностью, а затем преобразует их в одиночные/целочисленные массивы. Вы можете сэкономить временное использование памяти (и время), выполнив:

input = rand(size, 1, 'single');
output = zeros(size, 1, 'int8') - 1;
person Ray    schedule 27.10.2010
comment
Отличные предложения Рэй. Ваше решение увеличивает время ‹ 10%, практически не используя память. Я думаю, это сработает. Потрясающий! Большое спасибо!!! - person ggkmath; 28.10.2010
comment
Это как-то нелогично, но, судя по моим экспериментальным результатам, увеличение chunkSize с 1e7 увеличивает время выполнения, тогда как его уменьшение ускоряет время выполнения (я ожидал обратного). Хотя все еще работает. - person ggkmath; 28.10.2010
comment
Нет, слишком сильное уменьшение chunkSize начинает увеличивать время выполнения. chunkSize ~1e6 кажется оптимальным. - person ggkmath; 28.10.2010

Возможно, sign периодически преобразует ввод в double.

В любом случае, если все в порядке, если output равно 1 для положительного и 0 для отрицательного или нуля, вы можете попробовать

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 На самом деле, я вижу кратковременный всплеск использования памяти даже для этого решения. Может это связано с многопоточностью? В любом случае, проблема со скоростью возникает из-за того, что вы начинаете листать страницы, что замедляет все до минимума.

person Jonas    schedule 27.10.2010
comment
К сожалению, мне нужно, чтобы выходной массив был равен 1, чтобы указать, что входной элемент положительный, -1 для отрицательного и 0 для выходных значений, точно равных 0 (точно так же, как возвращалась бы функция «знак»). - person ggkmath; 28.10.2010