turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

Find a Community

- Home
- /
- SAS Programming
- /
- Base SAS Programming
- /
- Int gives wrong number

Topic Options

- RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

03-13-2015 07:24 AM

Hi guys,

i have a problem. - Im trying to truncate a number by the following procedure:

&result. = int(round(&array.[&counter.],0.000000000000001)*(10**&array.[&counter.-1]))*(10**-&array.[&counter.-1]);

where &counter. is the number which need to be truncated, and &counter.-1 is the number og digits i want to truncate with.

For curtain numbers, this fails. - An example;

int(round(67.1,0.000000000000001)*(10**6))*(10**-6);

which gives 67.09999999.

I have come to the conclusion, that it is the int function, which is the problem;

data _null_;

**number = 67.1*****100000**;

number_int = int(number);

put number;

run;

This returns "6709999" as an example.

Any ideas what to do, to not run into this problem ?

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to JakobKrogh

03-13-2015 07:37 AM

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to JakobKrogh

03-13-2015 10:51 AM

There is nothing wrong with INT() function. By ROUNDING() you have reduced the precision with which the number can be stored. You can see the same effect by reducing the number of storage bytes.

Try this program to see the impact of throwing away some of the precision from a number like one tenth that cannot be represented exactly using binary numbers.

data _null_;

fraction= 67 + 1/10 ;

do trunc=8 to 3 by -1 ;

number=trunc(fraction,trunc);

number_int= int(round(number,0.000000000000001)*(10**6))*(10**-6);

put trunc= number= number_int=;

end;

run;

trunc=8 number=67.1 number_int=67.099999

trunc=7 number=67.1 number_int=67.099999

trunc=6 number=67.1 number_int=67.099999

trunc=5 number=67.099999905 number_int=67.099999

trunc=4 number=67.099975586 number_int=67.099975

trunc=3 number=67.09375 number_int=67.09375

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to JakobKrogh

03-13-2015 12:01 PM

Move your exponents around so that you can round() to an integer.

This:

number_int= int(round(number,**0.000000000000001**)*(**10******6**))*(**10****-**6**);

Will become this:

number_int= round(number*(**10******15**),**1**) *(**10****-**15**);

Or to make it easier for your formula:

number_int= round(number*(**10****(9+6)),**1**) *(**10****(-9-6**)**);

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

03-13-2015 09:00 PM

Hi Tom

I have no doubt that this is about precision and binary storage of floating point numbers but I still can't fully understand what's going on here. Can you please try and elaborate/explain a bit more?

In below sample code what I don't understand:

- Why can't I see the difference when printing the numbers using format "32.24"

- Why is there no difference in "case 2"?

data _null_;

/** case1: 6710000 **/

put / '***** case1: 6710000 ******';

number_calc = 67.1 * 100000;

number_fixd = 6710000;

number_diff= number_fixd - number_calc;

put number_calc= 32.24;

put number_fixd = 32.24;

put number_diff = 32.24 /;

put number_calc = binary64.;

put number_fixd = binary64.;

/** case2: 10000 **/

put / '***** case2: 10000 ******';

number_calc = 0.1 * 100000;

number_fixd = 10000;

number_diff= number_fixd - number_calc;

put number_calc= 32.24;

put number_fixd = 32.24;

put number_diff = 32.24 /;

put number_calc = binary64.;

put number_fixd = binary64.;

stop;

run;

******* case1: 6710000 ********

**number_calc=6710000.000000000000000000000000**

**number_fixd=6710000.000000000000000000000000**

**number_diff=0.000000000931322574615470**

**number_calc=0100000101011001100110001011101111111111111111111111111111111111**

**number_fixd=0100000101011001100110001011110000000000000000000000000000000000**

******* case2: 10000 ********

**number_calc=10000.000000000000000000000000**

**number_fixd=10000.000000000000000000000000**

**number_diff=0.000000000000000000000000**

**number_calc=0100000011000011100010000000000000000000000000000000000000000000**

**number_fixd=0100000011000011100010000000000000000000000000000000000000000000**

Thanks

Patrick

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to JakobKrogh

03-13-2015 07:45 PM

I concur with JakobKrogh that the issue is with the int() function.

data _null_;

number = 67.1*100000;

number_int1 = int(number);

number_int2 = int(number+0.000000001);

number_int3 = int(number+0.0000000001);

number_int4 = round(number,1);

put number= number_int1= / number_int2= number_int3= / number_int4=;

run;

one gets the following:

number=6710000 number_int1=6709999

number_int2=6710000 number_int3=6709999

number_int4=6710000

it turns out that:

int(number+0.0000000005) = 6710000

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to billfish

03-13-2015 08:19 PM

Nope. Still the same problem. You cannot represent that many distinct decimal digits using binary floating numbers.

Try this one.

**data** _null_;

number0 = **67.1** * **10******5**;

do i=-**1** to -**10** by -**1**;

number1 = number0+**10****i ;

put i= Z3. +**1** number1 =**20.12** ;

end;

**run**;

i=-01 number1=6710000.100000000000

i=-02 number1=6710000.010000000000

i=-03 number1=6710000.001000000000

i=-04 number1=6710000.000100000000

i=-05 number1=6710000.000010000000

i=-06 number1=6710000.000001000000

i=-07 number1=6710000.000000100000

i=-08 number1=6710000.000000010000

i=-09 number1=6710000.000000000000

i=-10 number1=6710000.000000000000

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to billfish

03-13-2015 08:30 PM

Here's another fun one.

**data** _null_;

one_tenth=**0.1**;

one = **1**;

do _n_=**1** to **10** ; ten_tenths + one_tenth; end;

diff = one - ten_tenths ;

put (_all_) (= best32.);

**run**;

one_tenth=0.1 one=1 ten_tenths=1 diff=1.1102230246251E-16

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to JakobKrogh

03-14-2015 04:04 AM

Computers are not doing the math in the decimal approach. They are BINARY, thare are 10 ways to understand that are: yes/no.

See the docs SAS(R) 9.4 Language Reference: Concepts, Fourth Edition the decimal value 0.1 is an infinitely repeating reciproke in binary just like 1/3 =0.333... (wat is the last precision?)

Do the math the same in binary just as the processors (it is about that hardware level) are doing.

---->-- ja karman --<-----

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to jakarman

03-14-2015 08:07 AM

This fun topic -- numeric precision in SAS -- comes up quite a bit. Jaap is correct: floating point math in computers is not the same as if you worked it out by hand. There is an IEEE standard for how floating point numbers are represented in computers, and SAS follows that standard.

More here:

http://blogs.sas.com/content/sasdummy/2012/03/01/precision-in-sas-numbers/

Also this fun one: what is the difference between 0 and -0?

Chris