问题
Although I have come up with a work-around using multiple if / else if
statements, I am curious in knowing what looks wrong with my case
statements, illustrated below:
function [ar_vo,bucket] = revEng(v)
...
s=solve(solve>0) * sqrt(T);
ar_vo=s;
bucket=ri(ar_vo);
%%%%%%%%%%%%%%%%%%%%%
function bucket = ri(ar_vo)
% switch(ar_vo)
% case ((ar_vo >= 0)&&(ar_vo < 0.005)) (1)
% bucket=1;
% case ((ar_vo >= 0.005)&&(ar_vo < 0.02)) (2)
% bucket=2;
% case ((ar_vo >= 0.02)&&(ar_vo < 0.05)) (3)
% bucket=3;
% case ((ar_vo >= 0.05)&&(ar_vo < 0.1)) (4)
% bucket=4;
% case ((ar_vo >= 0.1)&&(ar_vo < 0.15)) (5)
% bucket=5;
% case ((ar_vol >= 0.15)&&(ar_vol < 0.25)) (6)
% bucket=6;
% case (ar_vo >= 0.25) (7)
% bucket=7;
% otherwise
% error('MATLAB:RI Bucket:NotAvailable.'); (8)
% end
%
Given ar_vo = 0.073...
while debugging the code, it skips case (4)
for some reasons and reaches case (8)
...
Inefficient but working solution with multiple if / else if
:
if ((ar_vo >= 0)&&(ar_vo < 0.005))
bucket=1;
else if ((ar_vo >= 0.005)&&(ar_vo < 0.02))
bucket=2;
else if ((ar_vo >= 0.02)&&(ar_vo < 0.05))
bucket=3;
else if ((ar_vo >= 0.05)&&(ar_vo < 0.1))
bucket=4;
else if ((ar_vo >= 0.1)&&(ar_vo < 0.15))
bucket=5;
else if ((ar_vo >= 0.15)&&(ar_vo < 0.25))
bucket=6;
else if (ar_vo >= 0.25)
bucket=7;
else
error('MATLAB:RI Bucket:NotAvailable.');
end
end
end
end
end
end
end
回答1:
The case
expressions for your switch
statement cannot be conditionals in MATLAB. They must be values.
switch thing
case 1
% do thing
case {2, 3}
% do other thing
otherwise
end
So what MATLAB is doing in your case, is that it is converting your conditionals into values. So when you supply a value of 0.073 what MATLAB sees is this.
switch 0.73
case 0
case 0
case 0
case 1
case 0
case 0
case 0
otherwise
end
Since 0.73 obviously doesn't match any of those values you fall through to the otherwise
and receive the error.
This is why switch statements are really only best for categorical data where you are comparing the input value against exact possible values (obviously not good for a floating point number).
A crazy solution
If you REALLY want to keep this as a switch statement you could do a little trickery and actually make your switch expression simply "1" (true
) and it will behave as you want it to.
switch(1)
case ((ar_vo >= 0)&&(ar_vo < 0.005))
bucket=1;
case ((ar_vo >= 0.005)&&(ar_vo < 0.02))
bucket=2;
case ((ar_vo >= 0.02)&&(ar_vo < 0.05))
bucket=3;
case ((ar_vo >= 0.05)&&(ar_vo < 0.1))
bucket=4;
case ((ar_vo >= 0.1)&&(ar_vo < 0.15))
bucket=5;
case ((ar_vo >= 0.15)&&(ar_vo < 0.25))
bucket=6;
case (ar_vo >= 0.25)
bucket=7;
otherwise
error('MATLAB:RI Bucket:NotAvailable.');
end
Please don't actually do this.
A Real Solution
One sane approach is to use a series of if/elseif statements (as opposed to your long tree of if else if
statements). This is a good approach (and is well-suited to floating point numbers) as it simply checks if that number is within a given range.
if ((ar_vo >= 0)&&(ar_vo < 0.005))
bucket=1;
elseif ((ar_vo >= 0.005)&&(ar_vo < 0.02))
bucket=2;
elseif ((ar_vo >= 0.02)&&(ar_vo < 0.05))
bucket=3;
elseif ((ar_vo >= 0.05)&&(ar_vo < 0.1))
bucket=4;
elseif ((ar_vo >= 0.1)&&(ar_vo < 0.15))
bucket=5;
elseif ((ar_vo >= 0.15)&&(ar_vo < 0.25))
bucket=6;
elseif (ar_vo >= 0.25)
bucket=7;
else
error('MATLAB:RI Bucket:NotAvailable.');
end
The Best Solution
What I personally would do though, would be to remove all of that code and simply replace it with the following statements.
lowerlimits = [0, 0.005, 0.02, 0.05, 0.1, 0.15, 0.25]
upperlimits = [lowerlimits(2:end), inf];
bucket = find(ar_vo >= lowerlimits & ar_vo < upperlimits);
if isempty(bucket)
error('MATLAB:RI Bucket:NotAvailable.');
end
In this approach I compare ar_vo
to all ranges simultaneously and then get the bucket
value by using the index of the match. If there was no bucket assigned, there was no match, and bucket
is an empty array.
This drastically reduces the chance of copy/paste errors and makes it easier if you want to modify the conditions at a later date. It is likely also more performant particularly for values > 0.25 which would have to traverse your entire if/elseif
construct.
回答2:
Building upon Suever's answer, and considering that you're actually trying to solve a data-binning problem, if you have R2015a or later, you can also use the built-in discretize function to achieve the same thing; e.g.:
function bucket = ri(ar_vo,edgz)
if nargin < 1
edgz = [0, 0.005, 0.02, 0.05, 0.1, 0.15, 0.25, inf];
end
bucket = discretize(ar_vo,edgz);
if isnan(bucket)
error('MATLAB:RI Bucket:NotAvailable.');
end
end
来源:https://stackoverflow.com/questions/35919254/multiple-case-statements-on-interval-within-nested-functions