BookmarkSubscribeRSS Feed
KoryeoVitamin
Calcite | Level 5

I have two values, A and B, which are 1632 and 5 each. And i wanna get the value of A divided by B by the unit of percent.

So the result should be 1632 / 5 * 100 = 32640  (multiplying 100 to express the value in % unit)

 

I have just used the INT function like this,

 RATE = INT( A / B * 100);

however, the results is 32639, not 32640.

So i tried like this,

Rate = A / B * 100;

then it turns out that the result is exactly what i want, 32640.

 

What is the cause of this phenomena...?

6 REPLIES 6
PeterClemmensen
Tourmaline | Level 20

Works fine to me? 

 

data _null_;
    a=1632; b=5;
    rate=(a/b)*100;
    put rate=;
run;
andreas_lds
Jade | Level 19

@PeterClemmensen : the problem is that

int(a / b * 100) ^= a / b * 100

But it should be the same. It seems as if the function int applied to the result of a / b before the multiplication takes place.

Kurt_Bremser
Super User

@andreas_lds wrote:

@PeterClemmensen : the problem is that

int(a / b * 100) ^= a / b * 100

But it should be the same. It seems as if the function int applied to the result of a / b before the multiplication takes place.


Absolutely not. It's "only" the classic "binary representation of decimal fractions" problem, confounded by the multiplication by 100.

Just run this code:

data _null_;
x1 = 1632/5;
x2 = x1 * 100;
x3 = 32640 - x2;
put x3 best32.;
run;

And you will see that x2 is just slightly smaller than 32640, but the difference is big enough to exceed the fuzz factor of the int() function (which is 1E-12).

It's the old bottom line: whenever you have fractions, apply the round() function in an appropriate place before continuing.

andreas_lds
Jade | Level 19

@Kurt_Bremser wrote:

@andreas_lds wrote:

@PeterClemmensen : the problem is that

int(a / b * 100) ^= a / b * 100

But it should be the same. It seems as if the function int applied to the result of a / b before the multiplication takes place.


Absolutely not. It's "only" the classic "binary representation of decimal fractions" problem, confounded by the multiplication by 100.

 


I just wanted to say that the problem was not that the division without applying int-function didn't work, but that the result differed from the result expected by @KoryeoVitamin - at least that was my interpretation of the initial post.

andreas_lds
Jade | Level 19

@KoryeoVitamin wrote:

 

What is the cause of this phenomena...?


 

Using the format binary64. shows what happens:

data _null_;
   format result expected binary64.;
   expected=32640;
   a=1632; 
   b=5;
   result=(a/b)*100;

   put expected=;
   put '  ' result=;
run;

/*
expected=0100000011011111111000000000000000000000000000000000000000000000
  result=0100000011011111110111111111111111111111111111111111111111111111
*/

So even without using int-function, the result does not match the expected value. Numeric precision is the culprit, see https://support.sas.com/documentation/cdl/en/lrcon/62955/HTML/default/viewer.htm#a000695157.htm for a lengthy explanation.

One solution is to use round instead of int.

hashman
Ammonite | Level 13

@KoryeoVitamin :

When you divide 1632 by 5 first, you're producing a fractional value stored as real binary with certain approximation; then when you multiply by 100, the result is also approximate between 32639 and 32640. When you "look" at the value through the mask of the BESTw. format you're using implicitly, it rounds the internally stored value up to 32640. BESTw. is not a WYSIWYG; it's WYSINWIG. To see the real value, you need the RB8. (displaying the value exactly using the radix 256), HEX16. (radix 16), or BINARY64. (radix 2) format. Since RB8. includes unprintable characters, it's not too informative, so let's see what happens with radix 16:

 

data _null_ ;                        
  retain a 1632 b 5 x 32639 y 32640 ;
  r = a / b * 100 ;                  
  i = int  (r) ;                    
  c = ceil (r) ;                    
  put (r i c x y ) (=hex16./) ;      
run ;                                

Result:

 

 

r=40DFDFFFFFFFFFFF
i=40DFDFC000000000
c=40DFE00000000000
x=40DFDFC000000000
y=40DFE00000000000

As you see, I=X and C=Y. The INT (same as FLOOR in this case) and CEIL functions act upon the real value of the computation R and round it down and up to the nearest integer accordingly. 

 

 

If you want to avoid enigmas of this sort, deal with integers, i.e. multiply first to get a value divisible by the denominator exactly:

 

data _null_ ;                        
  retain a 1632 b 5 x 32639 y 32640 ;
  r = a * 100 / b ;                  
  i = int  (r) ;                     
  c = ceil (r) ;                     
  put (r i c x y ) (=hex16./) ;      
run;                                 

In this case, you get:

r=40DFE00000000000
i=40DFE00000000000
c=40DFE00000000000
x=40DFDFC000000000
y=40DFE00000000000

That is, all the values except of X (which corresponds to 32639) are exactly 32640.

 

Kind regards

Paul D.

 

 

  

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 881 views
  • 0 likes
  • 5 in conversation