using IF and && together

hello I have this prog that I combine if and & in my first prog in the line of the if the expression before the && is correct but the expression after the && is wrong it should give me an error when j is equal to 6 at that time it will read(x(j+1) =x(7) and I d not have x(7) but it does not. however if I write in the line of the if, this statement
[ if x_new(i)<x(j+1)&&x_new(i)>x(j)]
it gives the error
why when I write x_new(i)<x(j+1) after the && it does not give me an error? ===========================================================================
clc
clear all
x=0:0.2:1;
y=[0 0.199 0.389 0.565 0.717 0.84];
x_new=[0.1 0.33];
for i=1:length(x_new)
for j=1:length(x)
if x_new(i)>x(j) && x_new(i)<x(j+1)
y_new(i)=(((y(j+1)-y(j))/(x(j+1)-x(j)))*(x_new(i)-x(j)))+y(j)
end
end
end
your help is appreciated thank you Zhina

 Accepted Answer

dpb
dpb on 4 Feb 2018
The "why" is because the && operator "short-circuits"; IOW, if the first condition is met so the answer is known from the first condition irrespective of the latter then the latter isn't ever computed as there's no need for it.
If you write it in the other order, then MATLAB will evaluate the expression in the order it is written and so try to make the test and discover an "out-of-range" error when you try to reference x(j+1) where j=length(x).
To fix this, don't try to access elements outside the array; fix the for...end loop indices such that only reference elements in range in case the first test isn't satisfied. Of course, then you'll need some other error-checking as you'll have given the algorithm data that is outside the range.
for j=1:length(x)-1 % keep references to x(j+1) in bounds; limit upper loop limit

12 Comments

ZM
ZM on 4 Feb 2018
Thank you for your answer I know that if I put [for j=1: length(x)-1] will not give error in other order I did not know that & only check the first expression and the other not how can I write this two expression in if that both of them should be checked x_new(i)>x(j) x_new(i)<x(j+1) is there is away?
Thank you
ZM
ZM on 4 Feb 2018
both expression before and after the & will be checked in my prog in either order otherwise, it will not give me the right value
but my problem is why when I have A&B when A is true and B is wrong it should say B is not available why does it not check B when A is true?
according to the circuit, it says if the first expression is false (A) there is no need to check the second (B). this correct what about B and A? if A is True it should check B? am I right?
Thank you for your help
dpb
dpb on 4 Feb 2018
You are correct; sorry, I don't know why I was thinking "OR" not "AND" even though the && operator is staring me in the face...old age does things like that to one, I'm afraid; I seem to notice it more and more.
Anyway, you never get the opportunity to check the last element as you've written the algorithm because you'll reach the loop limit first.
The better was is as Guillaume shows, use interp1 or if you want to write it yourself, use find with the optional parameter to return only one element, except do the reverse lookup instead of forward. Then you'll have the first position for which your looked for element is smaller than that in the lookup table (or empty if outside the range).
ZM
ZM on 5 Feb 2018
Actually, I know about interp1 command. I wrote this code for my students and in line 7 I wrote (for j=1: length(x)-1 ) but one my students ask me that when I write ( for j=1: length(x)) it does not give an error. I was very sure that if I write length(x) it should give the error but it did not. Thank you for your help anyway, I appreciate it.
I'll admit I'm puzzled with the loop limit on length(x) and the case with & as well. I tried a couple things to force its hand...
1. disp() the logic terms inside the IF to verify....expected results given the behavior observed...
>> for i=1:length(x_new)
for j=1:length(x),
if (x_new(i)>x(j) & x_new(i)<x(j+1))
disp([x_new(i)>x(j) x_new(i)<x(j+1) x_new(i)>x(j) & x_new(i)<x(j+1)])
y_new(i)=(((y(j+1)-y(j))/(x(j+1)-x(j)))*(x_new(i)-x(j)))+y(j)
end
end
end
1 1 1
y_new =
0.0995 0.3225
1 1 1
y_new =
0.0995 0.3225
>>
2. Try to show the results outside the IF for the entire loop...as expected, when force Matlab to output the result, then the symptom appears...
>> for i=1:length(x_new)
for j=1:length(x),disp([x_new(i)>x(j) x_new(i)<x(j+1) x_new(i)>x(j) & x_new(i)<x(j+1)]),
if (x_new(i)>x(j) & x_new(i)<x(j+1))
y_new(i)=(((y(j+1)-y(j))/(x(j+1)-x(j)))*(x_new(i)-x(j)))+y(j)
end
end
end
1 1 1
y_new =
0.0995 0.3225
0 1 0
0 1 0
0 1 0
0 1 0
Index exceeds matrix dimensions.
>>
3. Is something peculiar about the FOR loop isn't executed? No, that seems ok...
>> for i=1:length(x_new)
for j=1:length(x),disp([i j]),
if (x_new(i)>x(j) & x_new(i)<x(j+1))
y_new(i)=(((y(j+1)-y(j))/(x(j+1)-x(j)))*(x_new(i)-x(j)))+y(j)
end
end
end
1 1
y_new =
0.0995 0.3225
1 2
1 3
1 4
1 5
1 6
2 1
2 2
y_new =
0.0995 0.3225
2 3
2 4
2 5
2 6
>>
And, finally, the piece de resistanz...
4.
>> for i=1:length(x_new)
for j=1:length(x),disp([i j]),
if (x_new(i)>x(j) & x_new(i)<x(j+1)),disp([i j x_new(i)>x(j) & x_new(i)<x(j+1)]),
y_new(i)=(((y(j+1)-y(j))/(x(j+1)-x(j)))*(x_new(i)-x(j)))+y(j)
end
end
end
1 1
1 1 1
y_new =
0.0995 0.3225
1 2
1 3
1 4
1 5
1 6
2 1
2 2
2 2 1
y_new =
0.0995 0.3225
2 3
2 4
2 5
2 6
>>
I think this is worthy of a Tech Support query as to "How?" and "Is this expected behavior, and if so, why?"
It looks like the IF is functioning like a TRY...CATCH...END block by trapping the out of bounds error.
Be careful that && always does short-circuiting whereas & only does it inside an if or while statement. In all other cases, & does not short-circuit. This explains why your case 2 errors and not the others.
I would agree that this behaviour is undesirable and that & should never short-circuit.
dpb
dpb on 6 Feb 2018
I don't know how many times I've read that doc and never saw that note; I'll have to see if I've just missed it or that it is in later release(s). Unfortunately, on the new machine I don't have the significantly older versions installed to look at easily.
Anyway, that's just plain evil that it has differing behavior even if is documented. The doc ought to be far higher in the visibility chain than it is...
Thanks for the input, G...
Guillaume
Guillaume on 6 Feb 2018
Edited: Guillaume on 6 Feb 2018
I'll admit I only discovered that note recently. I thought that & never did short-circuit.
I've gone back through the documentation and the note appeared in R2014a. I completely agree that this behaviour is very undesirable but I doubt that mathworks will change that. I also agree that it should be documented a lot more prominently, particularly as it's not even mentioned in the doc of & and ||. For that I'll raise a bug report.
dpb
dpb on 6 Feb 2018
... back through the documentation and the note appeared in R2014a."
Thanks. By any chance to you have one of the preceding versions still installed to check if behavior has actually changed? I certainly didn't believe & ever short-circuited until just now...
I know(?) the short-circuiting operators && and were introduced later but the present documentation is also missing the note on when; even the "before R2006b" but I'm not sure it was that early.
Guillaume
Guillaume on 6 Feb 2018
Edited: Guillaume on 6 Feb 2018
I don't have anything earlier than R2017b installed. I just went back through the versioned docs on the website.
On the other hand, I can't think of many well-coded scenarios where it would actually matter that & does short-circuiting. Relying on side-effects always occuring in an if compound expression sounds like a bad idea.
ZM
ZM on 6 Feb 2018
Thank you for your answers. I really appreciate it. about trying on an older version, I use both 2013 and 2017. but the result was the same. Thank you again.
dpb
dpb on 7 Feb 2018
My question had to do with whether TMW changed this behavior with "classic" operators when they introduced the short-circuiting versions which, as noted, isn't documented just when but relatively recently although a number of releases ago by now...I'm guessing was after R14 but I haven't yet reinstalled earlier versions on new machine since old one crashed and burned. Unless some of those old clients call don't know there will be any need and even then probably just data and m-files will be all will really need.

Sign in to comment.

More Answers (1)

The simplest way to do what you want is to not bother at all with loops at all and use interp1
x=0:0.2:1;
y=[0 0.199 0.389 0.565 0.717 0.84];
x_new=[0.1 0.33];
y_new = interp1(x, y, x_new);
If you really wanted to do it yourself then you would not use a loop to scan x:
x=0:0.2:1;
y=[0 0.199 0.389 0.565 0.717 0.84];
x_new=[0.1 0.33];
y_new = zeros(size(x_new)); %always preallocate your output
for i = 1:numel(x_new)
j = find(x_new(i) > x(1:end-1) & x_new(i) < x(2:end)); %can't use && because working on vector
y_new(i) = (((y(j+1)-y(j))/(x(j+1)-x(j)))*(x_new(i)-x(j)))+y(j)
end
Note that I've left the comparisons as you wrote them. They would produce an incorrect result if x_new(i) is exactly equal to any of the x values.

Categories

Asked:

ZM
on 4 Feb 2018

Commented:

dpb
on 7 Feb 2018

Community Treasure Hunt

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

Start Hunting!