Background:
Comparing a reference method with a new method and calculating the resulting error between them, I want to fine tune the word length in the new method to minimize the error. As I am not aware of an analytical approach to achieve this, my idea was to iterate over the entire range of my input. However, it should be pointed out, that the word length of the input is very big (N=50). As a vector is to big to be processed, a for loop is the choice. Additionally I considered to use a Mex-File to speed things up.
As it seems that I can’t iterate in a Mex-File (for idx=1:2^N) for such a big N, the core of my calculations was put into a mex file and a for loop (parfor) was put around this core. The for loop just updates the input and gives it to the core.
Approach:
So the only open issue that came up was how to update the input efficiently.
This is what I tried:
Option 1)
Incrementing the input iteratively by adding one LSB (Least significant bit), however, I don’t see how I can use parfor here.
Option 2)
Updating the input by a “START_VALUE + IDX*LSB”.
Option 3)
Manipulating the binary representation of the fixed-point input.
The code:
close all
clear all
%% configure the fixed point data type
F = fimath('RoundingMethod','convergent','OverflowAction','Saturate');
WL_acc= 50; % wordl length
FL_acc= 40; % fractional word length
T.acc = fi([],1,WL_acc,FL_acc,'fimath',F); % typed
acc_lsb=lsb(T.acc); % LSB
x_start = cast(-14,'like',T.acc); % where to start to eval the range
x_val = x_start;
x_start_bin=x_start.bin; %binary format of start
x_start_bin_value=bin2dec(x_start_bin); %integer representation of start
%starting par
parpool(4);
maxIdx=2^18; % normally it should be 2^WL_acc , for testing smaller
% evaluation Option1, incrementing with one LSB
x_val = x_start;
disp(['Starting FOR option1: '])
tic
for idx=1:maxIdx
x_val(:)=x_val+acc_lsb;
end
toc
%eval option2, start+idx*LSB
disp(['Starting FOR option2: '])
x_val = x_start;
tic
for idx=1:maxIdx
x_val(:)=x_start+(idx-1)*acc_lsb;
end
toc
%eval option3, binary manipulation
disp(['Starting FOR option3: '])
tic
for idx=1:maxIdx
x_val=cast(0,'like',x_start);
res_bin=dec2bin(x_start_bin_value+idx);
x_val.bin=res_bin;
end
toc
% eval option2 with parfor
disp(['Starting ParFor option2: '])
tic
parfor idx=1:maxIdx
x_val=cast(x_start+(idx-1)*acc_lsb,'like',x_start);
end
toc
% eval option3 with parfor
disp(['Starting ParFor option3: '])
tic
parfor idx=1:maxIdx
x_val=cast(0,'like',x_start);
res_bin=dec2bin(x_start_bin_value+idx);
x_val.bin=res_bin;
end
toc
%closing workers
poolobj = gcp('nocreate');
delete(poolobj);
Result/Output
Starting FOR option1:
Elapsed time is 41.802891 seconds.
Starting FOR option2:
Elapsed time is 84.765272 seconds.
Starting FOR option3:
Elapsed time is 272.365962 seconds.
Starting ParFor option2:
Elapsed time is 87.836313 seconds.
Starting ParFor option3:
Elapsed time is 62.458244 seconds.
So it seems that with a normal for-loop Option2 is slower than Option1 and applying parfor for Option2 doesn’t seem to be more efficient that Option1. Option3 seem to be slow in the normal setup with a for-loop, however, it scales better with a parfor. So when using more than 4 workers, it could be better than Option1.
Question: The question is, what is a fast and precise way to change fi objects (or generate) them, in such a context when one is interested to evaluate the entire word length using parfor?