piecewise function evaluation using if-else statement

3 vues (au cours des 30 derniers jours)
cgo le 16 Mar 2015
Hi, I have this code for a 'piecewise function' to be evaluated.
t = -10:0.01:10;
if t<0
F(1,:) = 2.*t;
elseif t<8
F(1,:) = sqrt(t);
else F(1,:) = t+1;
end
I was wondering why the output is different from the one I was expecting.
Expected output: all numbers below 0 must be twice that number.
Output:
-9 -8.99000000000000 -8.98000000000000 -8.97000000000000 -8.96000000000000 -8.95000000000000 -8.94000000000000 -8.93000000000000 -8.92000000000000 -8.91000000000000 -8.90000000000000 -8.89000000000000 -8.88000000000000 -8.87000000000000 -8.86000000000000…….
0 commentairesAfficher -2 commentaires plus anciensMasquer -2 commentaires plus anciens

Connectez-vous pour commenter.

Réponse acceptée

Roger Stafford le 16 Mar 2015
Matlab's 'if' statement requires that if the following condition is a multiple-element logical vector, then every one of these must be true for it to be executed. The same applies to the 'elseif' statement. The consequence for your example is that only the 'else' part is executed, which accounts for your results.
What I believe you want is:
F(1,:) = (t<0).*(2*t)+(t>=8).*(t+1)+(t>=0).*(t<8).*sqrt(t);
Either that, or you can use a for-loop to apply your original tests to the elements of t one at a time.
http://www.mathworks.com/help/matlab/ref/if.html
where it states that "An expression is true when its result is nonempty and contains only nonzero elements (logical or real numeric). Otherwise, the expression is false."
2 commentairesAfficher AucuneMasquer Aucune
cgo le 16 Mar 2015
Wow, this is even more elegant that I thought. Thanks!
Walter Roberson le 10 Jan 2017
This condition .* value method often works really well. There is, however, a situation where it can give the wrong answer.
In each expression, the value is calculated for an element even if the condition is false for the element.
If the resulting value is finite, then it gets multiplied by the 0 corresponding to the condition being false for that element, and 0 .* finite gives 0 so you get out a 0 in that position, which is perfect for continuing on with the rest of the expression (one of the remaining expressions might give true and a non-zero value for that element.)
But if the resulting value calculation comes out as NaN or +/- inf, then when that is multiplied by 0, the result is NaN. And then when that NaN is added to anything else, the result is NaN, so you will get NaN in that position instead of some useful value.
A simple example is
(x == 0) .* 1 + (x ~= 0) .* (1./x)
The intent here is to give the value 1 at x = 0, and give 1/x otherwise. But the 1/x is calculated at all positions without checking the condition first, and so gives inf for 0, and the 0 (false) of x ~= 0, multiplied by inf, gives Nan instead of 0.
Karan's suggestion of using the new symbolic piecewise does not have this difficulty, but it does require that the input expression be symbolic, not plain numeric. If you have a numeric expression you might need to sym() it to use with piecewise()

Connectez-vous pour commenter.

Plus de réponses (2)

You can't use an if statement on a vector (or rather you can, but it is usually not the effect you wish to achieve, as in this case).
if t < 0
will test if the entire vector t is less than zero. It isn't. The else will test if the entire vector is less than 8. It isn't. Therefore the final else clause will be the one that kicks in and simply add 1 to all elements.
You can use vectorisation to achieve this as e.g.
t = -10:0.01:10;
F = t + 1;
F( t < 0 ) = 2 .* t( t < 0 );
F( t >= 0 & t < 8 ) = sqrt( t( t >= 0 & t < 8 ) );
Personally I would probably factor out that ugly condition that is used twice in the same line, but that is just semantics and personal preference.
1 commentaireAfficher -1 commentaires plus anciensMasquer -1 commentaires plus anciens
cgo le 16 Mar 2015

Connectez-vous pour commenter.

Sally Al Khamees le 21 Fév 2017
If you have R2016b and the Symbolic Math Toolbox installed, you can just use the piecewise function:
t = -10:0.01:10;
syms y(t);
y(t) = piecewise(t<0, 2*t, 0 <= t <= 8, sqrt(t), t+1);
fplot(y,t)
0 commentairesAfficher -2 commentaires plus anciensMasquer -2 commentaires plus anciens

Connectez-vous pour commenter.

Catégories

En savoir plus sur Assumptions dans Help Center et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by