NaN issue in fortran 90 - fortran90

I realize that if you write
Real (Kind(0.d0))::x,y
x = sqrt(-1.d0)
y = sqrt(-1.d0)
if (x == y) then
write(*,*)'yep, they are equals', x
endif
It compiles ok using ifort.
But nothing is written, the conditional is always false, did you notice that? why is this so?

NaN signifies not a number, and since there are many, different, reasons a calculation could give that result, they generally do not compare as equal against themselves. If you want to do nan-testing, fortran compilers that support the f2003 standard (which is recent versions of most compilers) have ieee_is_nan in the ieee_arithmetic module:
program testnan
use ieee_arithmetic
real (kind=kind(0.d0)) :: x,y,z
x = sqrt(-1.d0)
y = sqrt(-1.d0)
z = 1.d0
if ( ieee_is_nan(x) ) then
write(*,*) 'X is NaN'
endif
if ( ieee_is_nan(y) ) then
write(*,*) 'Y is NaN'
endif
if ( ieee_is_nan(x) .and. ieee_is_nan(y) ) then
write(*,*) 'X and Y are NaN'
endif
if ( ieee_is_nan(z) ) then
write(*,*) 'Z is NaN, too'
else
write(*,*) 'Z is a number'
endif
end program testnan
Compiling and running this program gives
ifort -o nan nan.f90
X is NaN
Y is NaN
X and Y are NaN
Z is a number
Unfortunately, gfortran still doesn't implement ieee_arithmetic as time of writing, so with gfortran you have to use the non-standard isnan.

Related

Need help in matrix dimension while converting from fortran to matlab

I have been working on a fortran code to convert it into the matlab. I am facing some issues with dimensioning! Following is the code which is giving me error
do 10 p = 1,m
d(p) = 0.d0
d(p) = x - x1(i,p) - x2(i,p) -
& double_sum(i,p,n,m,str,mot)
10 continue
double_sum = 0.d0
do 10 j = 1,m
do 20 k = 1,n
if (k .eq. i) then
else
double_sum = double_sum + mot(k,j,i,p)*str(k,j)
endif
20 continue
10 continue
to which I converted it into matlab as:
for p=1:m
d(p)=0;
double_sum = 0;
for j=1:m
for k=1:n
if k==i
else
double_sum = double_sum + mot(k,j,i,p)*str(k,j);
end
end
end
d(p)=x - x1(i,p) - x2(i,p)-double_sum(i,p,n,m,str,mot);
end
I am getting error of "index exceeding matrix".
The error line is for this part of my code:
d(p)=x - x1(i,p) - x2(i,p)-double_sum(i,p,n,m,str,mot);
So if I ignore double_sum(i,p,n,m,str,mot); this part, code runs perfectly.
I know the double_sum matrix is of 6D which looks suspicious to me, but I would like to have your support to successfully port this piece of fortran code.
Note:Asked the same question on matlab forum. But stackoverflow have more chances of people worked on fortran 77. Hence asking it here.
If the Fortran code in the Question is really everything, it may be a very rough snippet that explains how to calculate array d(:)
do 10 p = 1, m
d( p ) = x - x1( i, p ) - x2( i, p ) - double_sum( i, p, n, m, str, mot )
10 continue
with a function double_sum() defined by
double precision function double_sum( i, p, n, m, str, mot )
implicit none
integer, intent(in) :: i, p, n, m
double precision, intent(in) :: str( n, m ), mot( n, m, ?, ? )
integer j, k
double_sum = 0.d0
do 10 j = 1, m
do 20 k = 1, n
if (k .eq. i) then
else
double_sum = double_sum + mot( k, j, i, p ) * str( k, j )
endif
20 continue
10 continue
end
though it is definitely better to find the original Fortran source to check the context...(including how i and d(:) are used outside this code). Nevertheless, if we use the above interpretation, the corresponding Matlab code may look like this:
for p = 1:m
double_sum = 0;
for j = 1:m
for k = 1:n
if k == i
else
double_sum = double_sum + mot( k, j, i, p ) * str( k, j );
end
end
end
d( p ) = x - x1( i, p ) - x2( i, p ) - double_sum; % <--- no indices for double_sum
end
There is also a possibility that double_sum() is a recursive function, but because we cannot use the function name as the result variable (e.g. this page), it may be OK to exclude that possibility (so the Fortran code has two scopes, as suggested by redundant labels 10).
There is an error in your loops. The fortran code runs one loop over p=1:m, whose end is marked by the continue statement. Then, two nested loops over j and k follow.
Assuming, you know the size of all your arrays beforehand and have initialized them to the correct size (which may not be the case given your error statement) this is more along the lines of the fortran example you posted.
d = zeros(size(d));
for p=1:m
d(p)=x - x1(i,p) - x2(i,p)-double_sum(i,p,n,m,str,mot);
end
% add a statement here to set all entries of double sum to zero
double_sum = zeros(size(double_sum))
for j=1:m
for k=1:n
if k==i
else
double_sum = double_sum + mot(k,j,i,p)*str(k,j);
end
end
end
It is a little hard to give advice without knowledge of more parts of the code. are mot and str and double_sum functions? Arrays? The ambiguous choice of brackets in those two languages are hardly OPs fault, but make it necessary to provide further input.

Matlab calculate the product of an expression

I'm basicaly trying to find the product of an expression that goes like this:
(x-(N-1)/2).....(x+(N-1)/2) for even value of N
x is a value that I will set at the beginning that changes too but that is a different problem...
let's say for the sake of argument that for now x is a constant (ex x=1)
example for N=6
(x-5/2)(x-3/2)(x-1/2)(x+1/2)(x+3/2)*(x+5/2)
the idea was to create a row vector every element of which is each individual term (P(1)=x-5/2) (P(2)=x-3/2)...etc and then calculate its product
N=6;
x=1;
P=ones(1,N);
for k=(-N-1)/2:(N-1)/2
for n=1:N
P(n)=(x-k);
end
end
y=prod(P);
instead this creates a vector that takes only the first value of the epxression and then
repeats the same value at each cell.
there is obviously a fundamental problem with my loop but I just can't see it.
So if anyone can help with that OR suggest a better way to calculate the product I would be grateful.
Use vectorized commands
Why use a loop when you can use vectorized commands like prod?
y = prod(2 * x + [-N + 1 : 2 : N - 1]) / 2;
For convenience, you may want to define an anonymous function for it:
f = #(N,x) reshape(prod(bsxfun(#plus, 2 * x(:), -N + 1 : 2 : N - 1) / 2, 2), size(x));
Note that the function is compatible with a (row or column) vector input x.
Tests in MATLAB's Command Window
>> f(6, [2,2]')
ans =
-14.7656
4.9219
-3.5156
4.9219
-14.7656
>> f(6, [2,2])
ans =
-14.7656 4.9219 -3.5156 4.9219 -14.7656
Benchmark
Here is a comparison of rayreng's approach versus mine. The former emerges as the clear winner... :'( ...at least as N increases.
Varying N, fixed x
Fixed N (= 10), vector x of varying length
Fixed N (= 100), vector x of varying length
Benchmark code
function benchmark
% varying N, fixed x
clear all
n = logspace(2,4,20)';
x = rand(1000,1);
tr = zeros(size(n));
tj = tr;
for k = 1 : numel(n)
% rayreng's approach (poly/polyval)
fr = #() rayreng(n(k), x);
tr(k) = timeit(fr);
% Jubobs's approach (prod/reshape/bsxfun)
fj = #() jubobs(n(k), x);
tj(k) = timeit(fj);
end
figure
hold on
plot(n, tr, 'bo')
plot(n, tj, 'ro')
hold off
xlabel('N')
ylabel('time (s)')
legend('rayreng', 'jubobs')
end
function y = jubobs(N,x)
y = reshape(prod(bsxfun(#plus,...
2 * x(:),...
-N + 1 : 2 : N - 1) / 2,...
2),...
size(x));
end
function y = rayreng(N, x)
p = poly(linspace(-(N-1)/2, (N-1)/2, N));
y = polyval(p, x);
end
function benchmark2
% fixed N, varying x
clear all
n = 100;
nx = round(logspace(2,4,20));
tr = zeros(size(n));
tj = tr;
for k = 1 : numel(nx)
disp(k)
x = rand(nx(k), 1);
% rayreng's approach (poly/polyval)
fr = #() rayreng(n, x);
tr(k) = timeit(fr);
% Jubobs's approach (prod/reshape/bsxfun)
fj = #() jubobs(n, x);
tj(k) = timeit(fj);
end
figure
hold on
plot(nx, tr, 'bo')
plot(nx, tj, 'ro')
hold off
xlabel('number of elements in vector x')
ylabel('time (s)')
legend('rayreng', 'jubobs')
title(['n = ' num2str(n)])
end
function y = jubobs(N,x)
y = reshape(prod(bsxfun(#plus,...
2 * x(:),...
-N + 1 : 2 : N - 1) / 2,...
2),...
size(x));
end
function y = rayreng(N, x)
p = poly(linspace(-(N-1)/2, (N-1)/2, N));
y = polyval(p, x);
end
An alternative
Alternatively, because the terms in your product form an arithmetic progression (each term is greater than the previous one by 1/2), you can use the formula for the product of an arithmetic progression.
I agree with #Jubobs in that you should avoid using for loops for this kind of computation. There are cases where for loops perform fast, but for something as simple as this, avoid using loops if possible.
An alternative approach to what Jubobs has suggested is that you can consider that polynomial equation to be in factored form where each factor denotes a root located at that particular location. You can use poly to convert these factors into a polynomial equation, then use polyval to evaluate the expression at the point you want. First, generate your roots by linspace where the points vary from -(N-1)/2 to (N-1)/2 and there are N of them, then plug this into poly. Finally, for any values of x, put this into polyval with the output of poly. The advantage of this approach is that you can evaluate multiple points of x in a single sweep.
Going with what you have, you would simply do this:
p = poly(linspace(-(N-1)/2, (N-1)/2, N));
out = polyval(p, x);
With your example, supposing that N = 6, this would be the output of the first line:
p =
1.0000 0 -8.7500 0 16.1875 0 -3.5156
As such, this is saying that when we expand out (x-5/2)(x-3/2)(x-1/2)(x+1/2)(x+3/2)(x+5/2), we get:
x^6 - 8.75x^4 + 16.1875x^2 - 3.5156
If we take a look at the roots of this equation, this is what we get:
r = roots(p)
r =
-2.5000
2.5000
-1.5000
1.5000
-0.5000
0.5000
As you can see, each term corresponds to one factor in your polynomial equation, so we do have the right mindset here. Now, all you have to do is use p with your values of x into polyval to obtain your results. For example, if I wanted to evaluate that polynomial from -2 <= x <= 2 where x is an integer, this is the result I get:
polyval(p, -2:2)
ans =
-14.7656 4.9219 -3.5156 4.9219 -14.7656
Therefore, when x = -2, the result is -14.7656 and so on.
Though I would recommend the solution by #Jubobs, it is also good to check what the issue is with your loop.
The first indication that something is wrong, is that you have a nested loop over 2 variables, and only index with one of them to store the result. Probably you just need a single loop.
Here is a loop that you may be interested in that should do roughly what you need:
N=6;
x=1;
k=(-N-1)/2:(N-1)/2
P = ones(size(k));
for n=1:numel(k)
P(n)=(x-k(n));
end
y=prod(P);
I tried to keep the code close to the original, so hopefully it is easy to understand.

feval with multivariate function and vectorization

I need feval called with a bivariate function f and two vectors v1 and v2 (let us say that v1 are the x's and v2 the y's) to return a vector z=[f(v1(1),v2(1)) ... f(v1(n),v2(n)].
How can I do that ?
The following example does not work:
function z = f(x,y)
if x>0.5
z=x+y;
else
z=x+2*y;
end
end
indeed,
feval(f,[0.4 2 3],[4 5 6])
returns: [8.4 12 15]
instead of [8.4 7 9].
What is the correct syntax ?
The if condition doesn't work element-wise, as you seem to expect. Rather, the if branch is entered only if all the elements in the expression (x>0.5 in your case) evaluate to true.
To achieve what you want, change your function to
function z = f(x,y)
ind = x>.5;
z(ind) = x(ind) + y(ind);
z(~ind) = x(~ind) + 2*y(~ind);
end
Note that the logical index ind takes the place of your if.
For your particular function, the code could be simplified to
function z = f(x,y)
z = x + y + (x<=.5).*y;
end

What is wrong with this matlab function code?

I am not sure why this code wouldn't run. PLEASE HELP
function y = PdfMixUnfmBeta(x,alpha)
if x < 0
y = (1-alpha).*1/2;
elseif x >= 0
y = (1-alpha).*1/2 + alpha.*6*x*(1-x);
end;
when I execute this function as follows, there is an error
EDU>> x=-1:0.01:1;
EDU>> a=PdfMixUnfmBeta(x,0.4)
Error in PdfMixUnfmBeta (line 2)
if x < 0
The problem with your function is that you have written it assuming that x is a single value, and then you have passed it a vector. Your code cannot cope with this.
If you try to run your code with a single value, eg: a=PdfMixUnfmBeta(15,0.4) your function should run.
Lets look at what is actually wrong with your code, when I tried running your code I was given the following error:
Output argument "y" (and maybe others) not assigned during call
This indicates that the lines which assign to y are never actually executed. This indicates that neither of the conditional statements (x < 0 and x >= 0) ever evaluate as true. The if statements expects a scalar logical value, but in your example it is provided with a vector of logical.
So, to fix this you either need to deal with your x values one at a time by wrapping it in a for loop, e.g.:
function y = PdfMixUnfmBeta(x_vec, alpha)
for x = x_vec
%do your function here
end
end
Alternatively, you can vectorize your code, which is by far the preferable solution:
y = zeros(1,length(x));
% where x is < 0 use this formula
y(x < 0) = (1-alpha) .*(1/2);
% where x is >= 0 use this formula instead.
y(x >= 0) = (1-alpha) .* (1/2) + (alpha .* 6 .* x .* (1-x));
In the above solution I use logical indexing and change some of the * to .*. You may find it useful to look up the difference between * and .* and to read up on vectorization.

matlab: quick function that can produce NaN if x > 1

I am looking for a one-line function f = #(x) {something} that produces NaN if x >= 1, and either 0 or 1 if x < 1.
Any suggestions?
Aha, I got it:
f = #(x) 0./(x<1)
yields 0 for x < 1 and NaN for x>=1.
Here's a modification of Jason's solution that works for arrays. Note that recent versions of MATLAB do not throw divide-by-zero warnings.
>> f = #(x) zeros(size(x)) ./ (x < 1)
f =
#(x)zeros(size(x))./(x<1)
>> f(0:.3:2)
ans =
0 0 0 0 NaN NaN NaN
Update: a coworker pointed out to me that Jason's original answer works just fine for arrays.
>> f = #(x) 0./(x<1)
f =
#(x)0./(x<1)
>> f(0:.3:2)
ans =
0 0 0 0 NaN NaN NaN
Here's a less obvious solution (vectorized nonetheless):
f = #(x) subsasgn(zeros(size(x)), struct('type','()','subs',{{x>=1}}), nan) + 0
Basically its equivalent to:
function v = f(x)
v = zeros(size(x));
v( x>=1 ) = nan;
The +0 at the end is to always force an output, even if f called with no output arguments (returned in ans). Example:
>> f(-2:2)
ans =
0 0 0 NaN NaN
Here's a solution that won't risk throwing any divide-by-zero warnings, since it doesn't involve any division (just the functions ONES and NAN):
f = #(x) [ones(x < 1) nan(x >= 1)];
EDIT: The above solution is made for scalar inputs. If a vectorized solution is needed (which isn't 100% clear from the question) then you could modify f like so:
f = #(x) arrayfun(#(y) [ones(y < 1) nan(y >= 1)],x);
Or apply ARRAYFUN when calling the first version of the function f:
y = arrayfun(f,x);