BookmarkSubscribeRSS Feed
ballardw
Super User

Instead of a counted loop I think that you want a DO until (convergence). But you haven't said what the convergence limit would be. That would apparently be based on the two calculations. The iteration to track what has is happening probably should be a one record output for each iteration so you can see how values are changing. (i.e approaching convergence or not).

Thi_Oliveira
Calcite | Level 5

Thanks for the anwser. Do you have any example to share about this DO until convergence. 

I made this SAS program, but did not work again, because I can not see any changes in values.

data temp;
To=14;
Tb=4;
Tc=20;
k=(Tc-To)/(To-Tb);
l=(0.05**2)*(To-Tb)*((Tc-To)**k);
do i=1 to 50 by 1;
i+1= l/(((Tc-Tb)**(k+1))*((1-i)**k));
output;
end;
run;
ballardw
Super User

What do you think this this line of code does?

i+1= l/(((Tc-Tb)**(k+1))*((1-i)**k));

 I seriously doubt it does what you think, such as calculate the next value of i, which would be poor practice in most cases with an iterated loop as it can lead to infinite loops.

One example of why to be careful with modifying loop index variables inside a loop. The K counter is included to show what values of I look like at the end of the loop. The Leave instruction tells SAS to exit the loop when executed. It is easy to see that without that K and the Leave instruction the loop will never end.

data example2;
   do i=1 to 10;
      i=i-1;
      k+1;
      if k>100 then leave;
      output;
   end;
run;

 

If you want to use a calculated value inside a loop to control whether to continue you use a DO UNTIL or DO WHILE loop.

A brief example:

data example;
   j=7;
   do until (j le 0.1);
      j = j/3;
output; end; run;

You assign (calculate an initial value). Then you test if the value "converges", i.e is in some specific range of values. Above the test if the current value of J is <= 0.1.

If the comparison is false (not "converged") then the loop is entered. The J value, the loop control variable (or multiple variables) are recalculated. The the loop starts over with another test. The output shows the value at the bottom of the loop in this case. The last value for J shown will be the one that passed the comparison or "converged".

So the structure of your program should be

Establish all of the initial values, including your convergence criteria.

Test the value(s) for convergence.

If they don't converge then in the loop modify the calculation (all those K and K+1 variables), recalculate the convergence criteria value(s).

 

Some hints: Do not use exactly equal as the boundary (convergence) criteria and appropriate GE or LE are safer.

Test the code with a counter like my Example2 to break out of the loop after a few values so you can see if the values you need are moving in the expected manner.

Output the values per iteration so you can see those. Sometimes you discover that you have missed adjusting one of the variables you intended to.

 

back to this bit of code:

l/(((Tc-Tb)**(k+1))*((1-i)**k));

when i=1 then

(1-i)**k)   is (1-1)**k
or 
0**k

Which SAS will resolve as 0. So you have

l/(((Tc-Tb)**(k+1))*0);   See the problem yet?

0* anything = 0. So you have

l/0, throwing the divide by zero error.

 

So some return to algebra is indicated.

 

Kurt_Bremser
Super User

This statement:

i+1= l/(((Tc-Tb)**(k+1))*((1-i)**k));

is a so-called Sum Statement, and translates to this:

i = i + (1 = l/(((Tc-Tb)**(k+1))*((1-i)**k)));

which means that you add the result of a comparison to i, so you add either a 1 or a 0; since I doubt that the complex formula on the right will ever create an exact 1, this statement does in essence nothing. See it as an honourable mention in this year's Obfuscated SAS Code Contest.

FreelanceReinh
Jade | Level 19

Hello @Thi_Oliveira,

 

Try this approach:

data want;
/* Provide initial values and derived quantities */

To=14; Tb=4; Tc=20;
h=0.05;
c=10; /* Replace 10 with the real value of c in your application. */

k=(Tc-To)/(To-Tb);
j=h**(1/c)*(To-Tb)*(Tc-To)**k; /* (use j to avoid name conflict with L) */

eps=1e-12; /* used in convergence criterion (see chk_conv below) */
maxiter=1000; /* maximum number of iterations */

retain i L U 0; /* use RETAIN also to define variable order */
link chk_conv;
format dL dU best8.;
label L='L[i]'
      U='U[i]'
      dL='L[i] - L[i-1]'
      dU='U[i] - U[i-1]';

/* Perform iteration */

do i=0 to maxiter while(not conv);
  output;
  L=j/((Tc-Tb)**(k+1)*(1-L)**k);
  U=(j/((Tc-Tb)**(k+1)*(1-U)))**(1/k);
  link chk_conv;
end;

/* Compute final results (named Tb_ and Tc_) */

Tb_=Tb+L*(Tc-Tb);
Tc_=Tc-U*(Tc-Tb); /* Note the typo in the article! */
output;
return;

/* Check convergence criterion */

chk_conv:
  dL=dif(L);
  dU=dif(U);
  if i then conv=(.<abs(dL)<eps & .<abs(dU)<eps);
  return;
run;

proc print data=want label;
run;

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 19 replies
  • 1143 views
  • 1 like
  • 5 in conversation