I represents the global variable i.e the name I represents same variable inside and outside the function. Fact is first called when I = 1, which is the first value written. This value is
passed to the function's dummy argument N. The same I is now given the initial value 2 by the DO loop inside Fact, but since it is greater than N, the DO loop is not executed, so I still has the value 2
when Fact returns to be printed in the main program. However, I is now incremented to 3 in the
DO loop in the main program, which is the value it has when the second call to Fact takes place.
PROGRAM Factorial
IMPLICIT NONE
INTEGER I
DO I = 1, 10
PRINT*, I, Fact(I)
END DO
CONTAINS
FUNCTION Fact( N )
INTEGER Fact, N, Temp
Temp = 1
DO I = 2, N
Temp = I * Temp
END DO
Fact = Temp
END FUNCTION
END
and Once it completes I goes from 2 to N where now N =3..Now the function must returns I =3 to main program such that next I should be 4 in Do loop of main program, but when compiled and run..it only shows factor for 3,5,7 and 9.....My question is why it skip 4 or 6 or 8.
After exiting a loop the control variable gets the value of the upper bound + 1. However, it is illegal to modify the value of a loop control variable and anything can happen if you manage to do that despite the compiler's checks. It is an undefined behaviour then.
Not only that, you are aliasing the global I by using it as I as N at the same time inside the function. The compiler can probably perform various optimizations assuming that they are distinct when in fact they refer to the same variable. The program is therefore again illegal and unpredictable.
Consider this example and try to compile it with different optimization levels. You will get different answers:
i = 1
call s(i)
contains
subroutine s(j)
do k = 1, 10
j = i + j
end do
print *, j
end
end
Try it online!
This particular problem can probably be fixed by declaring i or the dummy argument target.
Related
This question already has an answer here:
Function in fortran, passing array in, receiving array out
(1 answer)
Closed 4 years ago.
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
IMPLICIT NONE
! FUNCTION TO CONVERT NUMBERS INTO ARRAYS OF NUMBERS, BY DIGIT
! PROBLEM 1: X IS NOT BEING PASSED
INTEGER :: NUM
INTEGER :: I,J
INTEGER :: LI(0:5) ! G95 COMPILER SAYS THAT 'LI ALREADY HAS BASIC TYPE INTEGER', DOESN'T RECOGNISE AS ARRAY
PRINT *,'NUM: ',NUM ! DEBUGGING LINE, CONFIRMS THAT X IS NOT BEING PASSED INTO THE FUNCTION
DO I = 0,5
J = 0
DO WHILE (J*10**(5-I)<=NUM)
J = J+1
END DO
J = J-1
LI(I) = J
NUM = NUM-(J*10**(5-I))
END DO
PRINT *,'LI: ',LI ! DEBUGGING LINE, SHOWS THAT FUNCTION IS AS IS SUPPOSED TO, EXCEPT FOR ON SOME SORT OF DEFAULT INTEGER
RETURN
END FUNCTION NUMTOLIST
PROGRAM NUMTOLISTTEST
IMPLICIT NONE
INTEGER FUNCTION, NUMTOLIST
INTEGER :: X
INTEGER :: F(1:6)
READ *,X
PRINT *,X
F = NUMTOLIST(X)
! PROBLEM 2: THE RESULT OF NUMTOLIST SHOULD BE A LIST, BUT F IS JUST BEING ASSIGNED NUM, NOT THE OUTPUT OF NUMTOLIST
PRINT *,F
READ *,X
END PROGRAM NUMTOLISTTEST
Here is my full code. As the name suggests, this is a test for a function of a larger code. There are several problems but the one that is most pressing is that for some reason a variable is not being passed to a function. I am using the silverfrost compiler, and for some reason although everything in the function itself is working as it should, it neither inputs nor returns properly. The input itself is completely disregarded, leading to num being undefined, and the return isn't being read as a list type, as F, when printed, is a list of the arbitrary number num took on. It's completely beyond me why any of this is happening, and I've been on and off looking at this for a couple of days.
Much more trivially, when I try to compile using G95, it won't. It claims that 'Li already has basic type 'Integer'', and then won't recognise Li as a list. The method I'm using to declare an integer as a list has worked in the past for me, and fits the documentation I've seen, so I'm confused why it's throwing an error.
I've been stuck on this for a while, and I just can't seem to fix it on my own. Whatever help is offered will be greatly appreciated, and thank you in advance.
You are indeed declaring a type for the variable LI twice in the function. Look:
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
! (...)
INTEGER :: LI(0:5)
Notice the INTEGER keyword before function declaration. It applies to the variable name declared as result in result(LI). The second declaration of LI gives the error.
Solutions:
Remove the INTEGER from the function declaration (preferred);
Remove the second type declaration of LI. You can specify a dimension without type declaration, with the dimension specification statement.
like this:
DIMENSION LI(0:5)
Besides that, to call a function with an array as a returning value, you will need an explicit interface.
so i had this segment of code in my C++ test today:
for(int i=10;i++;i<15){cout<<i;}
what is this supposed to output? and why ?
Thanks!
A for loop will run until either:
its 2nd argument evaluates as 0/false.
the loop body calls break or return, or throws an exception, or otherwise exits the calling thread.
The code you have shown may or may not loop indefinitely. However, it will not loop the 5 times you might be expected, because the 2nd and 3rd arguments of the for statement are reversed.
The loop should look like this:
for(int i = 10; i < 15; i++)
However, in the form you have shown:
for(int i = 10; i++; i < 15)
The loop will continue running as long as i is not 0. Depending on how the compiler interprets i++ as a loop condition, it may recognize that this will lead to overflow and just decide to ignore i and make the loop run indefinitely, or it may actually increment i and let overflow happen.
In the latter case, on every loop iteration, i will be incremented, and eventually i will overflow past the maximum value that an int can hold. At that time, i will usually wrap around to a negative value, since int is a signed type (though overflow behavior is not officially defined by the C++ standard, so the wrap is not guaranteed). Then the loop will keep running since i is not 0, incrementing i each time until it eventually reaches 0, thus breaking the loop.
In either case, the loop will end up calling cout << i many thousands/millions of times (depending on the byte size of int), or call it forever until the program is terminated.
what is this supposed to output? and why ?
That unconditionally do an signed int overflow.
So it is is Undefined behavior and can do anything.
For practical purposes, with any modern compiler this loop will continue forever. The reason for that is that the code is syntactically correct (however very incorrect semantically).
for(int i = 10; i++; i < 15)
means: start with i equal to 10. Check if i++ is true (which it will be, since integers are convertible to booleans, with non-0 values converted to true). Proceed with loop body, on every iteration performing comparison of i and 15 (just comparing, not checking the result, this is your increment expression), incrementing i and checking if it is non-0.
Since compilers understand that signed integers never overflow, i++ could never go to 0 when started with 10. As a result, optimizing compiler will remove the check altogether, and turn it into infinite loop.
Last, but not the least, learn to love compiler warnings. In particular, this code produces following:
<source>:4:29: warning: for increment expression has no effect [-Wunused-value]
for (int i = 10; i++; i < 15) {
~~^~~~
<source>:4:23: warning: iteration 2147483637 invokes undefined behavior [-Waggressive-loop-optimizations]
for (int i = 10; i++; i < 15) {
~^~
<source>:4:23: note: within this loop
for (int i = 10; i++; i < 15) {
^~
I have the following program:
program example
implicit none
integer::i, x1
real::x(10)=0
do i=10,1,-2
x(10-i)=2*i+1
enddo
x1=i*2-1
end program example
My problem is to determine the value of x1 but since variable i was never input or specified, how does Fortran determine the value of i used in the calculation of x1?
"since variable i was never input or specified"
This assumption is wrong. Inside the loop i takes exactly defined values 10, 8, 6, 4, 2.
After the loop finishes, the Fortran standard specifies that the value of i shall be the next value of the loop counter as if the loop still continued, so the value of i will be 0.
So the value of x1 will be 0*2 - 1 = -1 and it can be easily verified by adding print *, x1 at the end of the program.
But there is a different problem with your program as francescalus found out. On the first iteration the value of i is 10 and you are accessing x(10-i) which is x(0). This element does not exist, x has only elements from x(1) to x(10) so accessing x(0) is illegal and the behaviour of the whole program after that point is undefined.
What is the output of the following code:
int main() {
int k = (k = 2) + (k = 3) + (k = 5);
printf("%d", k);
}
It does not give any error, why? I think it should give error because the assignment operations are on the same line as the definition of k.
What I mean is int i = i; cannot compile.
But it compiles. Why? What will be the output and why?
int i = i compiles because 3.3.1/1 (C++03) says
The point of declaration for a name is immediately after its complete declarator and before its initializer
So i is initialized with its own indeterminate value.
However the code invokes Undefined Behaviour because k is being modified more than once between two sequence points. Read this FAQ on Undefined Behaviour and Sequence Points
int i = i; first defines the variable and then assigns a value to it. In C you can read from an uninitialized variable. It's never a good idea, and some compilers will issue a warning message, but it's possible.
And in C, assignments are also expressions. The output will be "10", or it would be if you had a 'k' there, instead of an 'a'.
Wow, I got 11 too. I think k is getting assigned to 3 twice and then once to 5 for the addition. Making it just int k = (k=2)+(k=3) yields 6, and int k = (k=2)+(k=4) yields 8, while int k = (k=2)+(k=4)+(k=5) gives 13. int k = (k=2)+(k=4)+(k=5)+(k=6) gives 19 (4+4+5+6).
My guess? The addition is done left to right. The first two (k=x) expressions are added, and the result is stored in a register or on the stack. However, since it is k+k for this expression, both values being added are whatever k currently is, which is the second expression because it is evaluated after the other (overriding its assignment to k). However, after this initial add, the result is stored elsewhere, so is now safe from tampering (changing k will not affect it). Moving from left to right, each successive addition reassigns k (not affected the running sum), and adds k to the running sum.
I have been trying to understand of this following C-program:
#include <stdio.h>
int arr[] = {1,2,3,4};
int count;
int incr(){
return ++count;
}
int main(){
arr[count++]=incr();
printf("%d %d",count,arr[count]);
return 0;
}
The program gives 1 2 as output,what I am not gtting is why the value of count is 1 here and not 2 (since there are two increments)?
The order of evaluation of operands of = operator is unspecified in arr[count++]=incr(); and since both the operands are trying to modify the same global variable count the result would be different on different compilers depending upon the order of evaluation.
EDIT
Actually the behavior is undefined (which means anything can happen) because "the prior value of the variable count is not accessed (only) to determine the value to be stored."
incr() will return either 1 or 2. It depends on whether the implementation first increments count and then calls incr(), or whether it first calls incr() and then increments count.
Please note that this choice does not mean that behavior is undefined. Since before a function is entered, and after a function is left, there is a sequence point at each point, both increments we have here are separated by a sequence point, so that the increment in main, if it started to happen before the call, will be finished once entering incr(), and if it happens after incr() was called, will not have yet started until incr() has left.
We have multiple scenarios here:
First do the increment for count++, then call incr(). This will write 2 into arr[0].
First call incr(), then do the increment for count++. This will write 1 into arr[1].
So, count is always 2, and arr[count] is always 3 (it wasn't overwritten). So it should output 2 3, not 1 2.
I think that if you do the following, you have more options
int main(){
arr[++count]=incr();
printf("%d %d",count,arr[count]);
return 0;
}
Now, the value read from ++count can be different than count+1, because there is nothing that stops incr() to be called after incrementing count but before reading it. In this case we have
First do the increment for ++count, then call incr(), then read from count. This will write 2 into arr[2].
First do the increment for ++count, then read from count, and then call incr(). This will write 2 into arr[1].
First call incr(), then do the increment for ++count and read from it. This will write 1 into arr[2].
In this case, you can either have output 2 2 or 2 1 or 2 3.