SAS中DO WHILE与DO UNTIL循环为何会在应终止后多执行一次循环体?
Hey there! This is a super common gotcha with floating-point number precision—let’s break down exactly what’s happening with both of your loops.
Problem 1: DO WHILE Loop Outputting 1.1
First, let’s recap your code:
data do_while; a = 0; do while (a<1); a = a+0.1; output; end; run;
You’d expect the loop to stop when a hits 1.0, right? Here’s why it doesn’t:
- The value
0.1can’t be represented exactly as a binary floating-point number (the format SAS uses for numeric variables). It’s an infinite repeating fraction in binary, so every time you add0.1, you’re actually adding a tiny approximation of 0.1. - After 10 additions, instead of getting exactly 1.0, you end up with a value very slightly less than 1.0 (something like
0.9999999999999999). - Since this value still satisfies
a<1, the loop runs one more time:abecomes0.9999999999999999 + 0.1 = 1.0999999999999999, which SAS displays as1.1in your dataset. Then the loop checksa<1again, which is false, so it terminates.
Problem 2: DO UNTIL Loop Also Outputting 1.1
Your DO UNTIL code:
data do_until; b=0; do until (b>=1); b=b+0.1; output; end; run;
Your logic about DO UNTIL (execute first, check condition second) is totally correct—here’s why you still get 1.1:
- Again, floating-point precision is the issue. After 9 additions,
bisn’t exactly0.9—it’s a tiny approximation slightly less than0.9. - Adding
0.1gives you a value still slightly less than 1.0 (like0.9999999999999999). Sinceb>=1is still false, the loop runs again:bbecomes1.0999999999999999(displayed as1.1), you output it, then the conditionb>=1finally evaluates to true, and the loop stops.
How to Fix This
To avoid floating-point precision headaches in loops like this, try one of these approaches:
Loop with integers instead: Calculate your decimal value using an integer counter—this eliminates approximation errors entirely:
data do_while_fixed; do i = 1 to 10; a = 0.1 * i; output; end; run;Use rounding in your condition: If you need to stick with decimal increments, round the value when checking the condition to account for tiny precision gaps:
data do_while_fixed; a = 0; do while (round(a, 0.1) < 1); a = a + 0.1; output; end; run;
You can verify the exact stored values by adding a put statement to your original code, like put a best32.;—this will show you the full precision of the number SAS is actually using, not just the rounded display value.
内容的提问来源于stack exchange,提问作者PoorDataAnalyst

