MATLAB Answers

Producing a NaN only where there is a NaN, zero otherwise

조회 수: 121(최근 30일)
John D'Errico
John D'Errico 22 Feb 2021
댓글: the cyclist 24 Mar 2021 18:58
This interesting question came up for me today. I was looking for a simple expression that can be used in a function handle, one that produces a NaN only for elements that are already NaN, but I want it to return 0 for any other element, including +/- inf.
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
That should qualify as a good list of the possible numbers in MATLAB that might be of interest.
I want my function to generate a result as the vector: [0 0 0 0 0 0 0 0 0 0 0 NaN].
For example, this fails:
broken1 = @(X) 0*X;
broken1(X)
ans = 1×12
NaN 0 0 0 0 0 0 0 0 0 NaN NaN
Though it is close. It suffers because 0*inf generates a NaN. An as pretty one is:
broken2 = @(X) X - X;
broken2(X)
ans = 1×12
NaN 0 0 0 0 0 0 0 0 0 NaN NaN
It fails for a similar reason, because inf-inf produces NaN.
A valid solution should work for arrays of any shape or size of course. Yes, it is trivial to write if I do it in an m-file. Thus...
nanZ(X)
ans = 1×12
0 0 0 0 0 0 0 0 0 0 0 NaN
function res = nanZ(X)
% returns a NaN ONLY for elements of X that are NaN. All other elements will generate zero.
res = zeros(size(X));
res(isnan(X)) = NaN;
end
As I said, trivial if I use an m-flle. More difficult if I wish to use a function handle. It may be a blind spot on my part. But as a puzzle, can you write a simple, robust one line expression to produce my desired result, expressed as a function handle? Vectorized, of course.
And yes, I'll admit this question has essentially zero value, since a valid solution exists in an m-file form. Have fun! (I'll post a spoiler as an answer if people cannot find a better solution than the one I found. My final solution required only 9 characters, but it was definitely non-obvious.)

답변(6개)

Stephen Cobeldick
Stephen Cobeldick 22 Feb 2021
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
Y = 0./(X==X)
Y = 1×12
0 0 0 0 0 0 0 0 0 0 0 NaN
  댓글 수: 4
John D'Errico
John D'Errico 22 Feb 2021
NIce. And it ties my solution of 9 characters. It will probably be more efficient than mine too.

댓글을 달려면 로그인하십시오.


Gustavo Lunardon
Gustavo Lunardon 24 Mar 2021 18:47
Added as an answer rather than a comment now
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
broken1 = @(X) 0./X.^0;
broken1(X)
Also works, 7 characters
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
broken1 = @(X) 0*X.^0;
broken1(X)
Works as well with 6 characters
Advantage is that you can put any number different than zero in the other elements by changing the multiplier
  댓글 수: 1
the cyclist
the cyclist 24 Mar 2021 18:58
Very nice!
It's a darn shame that
not(NaN)
does not yield NaN, because "NaN cannot be converted to logical". If it did, then
~X.^0
would be a sublime 5-character solution.

댓글을 달려면 로그인하십시오.


the cyclist
the cyclist 22 Feb 2021
편집: the cyclist 22 Feb 2021
First attempt:
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
broken = @(x) 1./((isnan(x)-1)/0); % 19 characters
broken(X)
ans = 1×12
0 0 0 0 0 0 0 0 0 0 0 NaN

the cyclist
the cyclist 22 Feb 2021
Second attempt ...
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
broken = @(x) 0./(isnan(x)-1); % 15 characters
broken(X)
ans = 1×12
0 0 0 0 0 0 0 0 0 0 0 NaN
  댓글 수: 2
the cyclist
the cyclist 23 Feb 2021
I overlooked the obvious improvement to this one:
broken = @(x) 0./~isnan(x); % 12 characters
I like the fact that this one avoids the annoying denominator parentheses

댓글을 달려면 로그인하십시오.


John D'Errico
John D'Errico 22 Feb 2021
편집: John D'Errico 22 Feb 2021
I'm always amazed at how many ways there are to accomplish anything in MATLAB. Here was my effort. It took me some time to think of my solution - why I posted the question. I had to find a call that would return a real number for any inputs, including inf and -inf. But I still needed it to return NaN for NaN input. Then i could just multiply by 0. atan fit perfectly. And since 0*NaN is still NaN, this was my solution:
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
unbroken = @(X) 0*atan(X);
unbroken(X)
ans = 1×12
0 0 0 0 0 0 0 0 0 0 0 NaN
Only 9 characters. But I am sure there is a better solution yet. And mine might not be terribly computationally efficient.
(Sadly, things like 0*sin(X) fails, because sin(inf) is NaN. But that would have saved a character.)
  댓글 수: 2
Stephen Cobeldick
Stephen Cobeldick 24 Mar 2021 17:03
@Gustavo Lunardon: very neat. Please add this as an answer!

댓글을 달려면 로그인하십시오.


Jan
Jan 24 Mar 2021 16:50
X = [-inf, -1, -eps, 0, realmin, 2, 1+i, pi, flintmax, realmax, inf, NaN];
V = [0, NaN];
F = @(X) V(isnan(X) + 1);
F(X)

태그

Community Treasure Hunt

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

Start Hunting!

Translated by