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

125 ビュー (過去 30 日間)
John D'Errico 2021 年 2 月 22 日
コメント済み: the cyclist 2021 年 3 月 24 日 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.)
2 件のコメント表示非表示 1 件の古いコメント
John D'Errico 2021 年 2 月 22 日
Yes indeed.

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

回答 (6 件)

Stephen Cobeldick 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 件のコメント表示非表示 3 件の古いコメント
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 2021 年 3 月 24 日 18:47
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 2021 年 3 月 24 日 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 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
0 件のコメント表示非表示 -1 件の古いコメント

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

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 件のコメント表示非表示 1 件の古いコメント
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

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

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 件のコメント表示非表示 1 件の古いコメント
Stephen Cobeldick 2021 年 3 月 24 日 17:03

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

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