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

1 回表示 (過去 30 日間)
John D'Errico
John D'Errico 2021 年 2 月 22 日
コメント済み: the cyclist 2021 年 3 月 24 日
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.)
  2 件のコメント
the cyclist
the cyclist 2021 年 2 月 22 日
Reminds me of the old MATLAB Golf contests!
John D'Errico
John D'Errico 2021 年 2 月 22 日
Yes indeed.

サインインしてコメントする。

回答 (6 件)

Stephen23
Stephen23 2021 年 2 月 22 日
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 件のコメント
the cyclist
the cyclist 2021 年 2 月 22 日
編集済み: the cyclist 2021 年 2 月 22 日
0./eq(X,X)
is a nice variant of this, but one additional character
John D'Errico
John D'Errico 2021 年 2 月 22 日
編集済み: John D'Errico 2021 年 2 月 22 日
NIce. And it ties my solution of 9 characters. It will probably be more efficient than mine too.

サインインしてコメントする。


Gustavo Lunardon
Gustavo Lunardon 2021 年 3 月 24 日
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 2021 年 3 月 24 日
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 2021 年 2 月 22 日
編集済み: the cyclist 2021 年 2 月 22 日
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 2021 年 2 月 22 日
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 件のコメント
John D'Errico
John D'Errico 2021 年 2 月 22 日
Also nice.
the cyclist
the cyclist 2021 年 2 月 23 日
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

サインインしてコメントする。


Jan
Jan 2021 年 3 月 24 日
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)

John D'Errico
John D'Errico 2021 年 2 月 22 日
編集済み: John D'Errico 2021 年 2 月 22 日
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 件のコメント
Gustavo Lunardon
Gustavo Lunardon 2021 年 3 月 24 日
編集済み: Gustavo Lunardon 2021 年 3 月 24 日
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
Stephen23
Stephen23 2021 年 3 月 24 日
@Gustavo Lunardon: very neat. Please add this as an answer!

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeNumeric Types についてさらに検索

タグ

Community Treasure Hunt

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

Start Hunting!

Translated by