BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
cgarciam80
Calcite | Level 5

Please help me understand why the column ending in "BAD" formats the input ending with 00 like that. I would have expected the same results.

 

DATA PAY_FILE ;

    LENGTH OUTSTANDING_BAL $ 15 ;

    FORMAT OUTSTANDING_BAL $CHAR15. ;

     INPUT  OUTSTANDING_BAL $ ;

     CARDS;

     000000000120584

     000000000005073

     000000000008371

     000000000001000

     000000000081000

     000000000009000

     ;

RUN;

 

DATA PAY_FILE;

SET PAY_FILE;

FORMAT OUTSTANDING_BAL_OK1 dollar20.2;

OUTSTANDING_BAL_OK1 = INPUT(STRIP(INPUT(CAT(SUBSTR(OUTSTANDING_BAL,1,LENGTH(OUTSTANDING_BAL)-2),".",SUBSTR(OUTSTANDING_BAL,LENGTH(OUTSTANDING_BAL)-1,2)),20.)),10.);

OUTSTANDING_BAL_OK2 = INPUT(STRIP(INPUT(CAT(SUBSTR(OUTSTANDING_BAL,1,LENGTH(OUTSTANDING_BAL)-2),".",SUBSTR(OUTSTANDING_BAL,LENGTH(OUTSTANDING_BAL)-1,2)),20.)),10.);

OUTSTANDING_BAL_BAD = INPUT(STRIP(INPUT(CAT(SUBSTR(OUTSTANDING_BAL,1,LENGTH(OUTSTANDING_BAL)-2),".",SUBSTR(OUTSTANDING_BAL,LENGTH(OUTSTANDING_BAL)-1,2)),20.)),DOLLAR20.2);

RUN;

 

cgarciam80_0-1593038886530.png

 

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

@cgarciam80 wrote:

My goal was to add a decimal point before the last to digits of the character field and made that a dollar amount. It worked for most of the values but those ending in "00" did not work. I realize I could have done it differently but I am still curious about why it did not work.


 

Let's deconstruct your nested function calls:

len=LENGTH(OUTSTANDING_BAL);
str1=SUBSTR(OUTSTANDING_BAL,1,len-2);
str2=SUBSTR(OUTSTANDING_BAL,len-1,2);
str3=CAT(str1,".",str2);
num1=INPUT(str3,20.);
str4=STRIP(num1);
OUTSTANDING_BAL_BAD = INPUT(str4,DOLLAR20.2);

Note that this might add spaces into STR3 depending on how long STR1 and STR2 get defined. Change CAT() to CATS() to prevent that.

 

So your big mistake is added those last two steps. NUM1 is the number you want.  By first converting it to a string and back to a number again you have introduced a point where there can be changes.  First the default conversion SAS will do when convert NUM1 into a character string so that the STRIP() function can operate on it is that it will use BEST12 to format the number.  So if the value needs more than 12 characters you will loose precision.  But second for integer values it will NOT insert an explicit decimal point into the string, so the implied decimal point of the DOLLAR20.2 informat will end up dividing any whole numbers by 100.

 

Are you just trying to create another text string? Or create a numeric variable?  If you want to create a string use the STR3 value with period inserted before the last two characters.  If you want to create a numeric variable then use the INPUT() function with the 20.2 informat. 

OUTSTANDING_BAL_BAD = INPUT(OUTSTANDING_BAL,20.2)

That .2 means that SAS should assume the decimal point is before the last two characters, when there is not one in the string being read.  That is it divides such values but 10**2.

If the string OUTSTANDING_BAL can contain commas and dollar signs you could use COMMA20.2 informat instead.  Note that the DOLLAR informat is just an alias for the COMMA informat.

 

View solution in original post

7 REPLIES 7
Tom
Super User Tom
Super User

Can you explain what you are trying to do?

cgarciam80
Calcite | Level 5

The input is a character field with length 15. (It comes from an external source but I created it here in order to ask my question). 

 

My goal was to add a decimal point before the last to digits of the character field and made that dollar amount. It worked for most of the fields but those ending in "00" did not work. I realized I could have done it differently but I am still curious about why it did not work.

Tom
Super User Tom
Super User

Do you know what the the decimal part of an INFORMAT does?

Example: 

DATA PAY_FILE ;
  LENGTH OUTSTANDING_BAL $ 15 ;
  INPUT  OUTSTANDING_BAL $ ;
CARDS;
000000000120584
00000000005073
0000000008371
000000001000
0000081000
00009000
123.45
;

data test;
  set pay_file;
  value0 = input(outstanding_bal,15.);
  value1 = input(outstanding_bal,15.1);
  value2 = input(outstanding_bal,15.2);
run;

proc print;
run;
Obs    OUTSTANDING_BAL       value0     value1      value2

 1     000000000120584    120584.00    12058.40    1205.84
 2     00000000005073       5073.00      507.30      50.73
 3     0000000008371        8371.00      837.10      83.71
 4     000000001000         1000.00      100.00      10.00
 5     0000081000          81000.00     8100.00     810.00
 6     00009000             9000.00      900.00      90.00
 7     123.45                123.45      123.45     123.45

 

cgarciam80
Calcite | Level 5

My goal was to add a decimal point before the last to digits of the character field and made that a dollar amount. It worked for most of the values but those ending in "00" did not work. I realize I could have done it differently but I am still curious about why it did not work.

Shmuel
Garnet | Level 18

You could either read the variable OUTSTANDING_BAL using informat 15.2 instead $

DATA PAY_FILE ;
    /* LENGTH OUTSTANDING_BAL $ 15 ; */
    FORMAT OUTSTANDING_BAL 15.2 ;
     INPUT  OUTSTANDING_BAL 15.2;
     CARDS;
     000000000120584
     000000000005073
     000000000008371
     000000000001000
     000000000081000
     000000000009000
     ;
RUN;

or you can repair it by:

 

Data pay_file;
   OUTSTANDING_BAL_OK = input(OUTSTANDING_BAL, 15.2);
run;
Tom
Super User Tom
Super User

@cgarciam80 wrote:

My goal was to add a decimal point before the last to digits of the character field and made that a dollar amount. It worked for most of the values but those ending in "00" did not work. I realize I could have done it differently but I am still curious about why it did not work.


 

Let's deconstruct your nested function calls:

len=LENGTH(OUTSTANDING_BAL);
str1=SUBSTR(OUTSTANDING_BAL,1,len-2);
str2=SUBSTR(OUTSTANDING_BAL,len-1,2);
str3=CAT(str1,".",str2);
num1=INPUT(str3,20.);
str4=STRIP(num1);
OUTSTANDING_BAL_BAD = INPUT(str4,DOLLAR20.2);

Note that this might add spaces into STR3 depending on how long STR1 and STR2 get defined. Change CAT() to CATS() to prevent that.

 

So your big mistake is added those last two steps. NUM1 is the number you want.  By first converting it to a string and back to a number again you have introduced a point where there can be changes.  First the default conversion SAS will do when convert NUM1 into a character string so that the STRIP() function can operate on it is that it will use BEST12 to format the number.  So if the value needs more than 12 characters you will loose precision.  But second for integer values it will NOT insert an explicit decimal point into the string, so the implied decimal point of the DOLLAR20.2 informat will end up dividing any whole numbers by 100.

 

Are you just trying to create another text string? Or create a numeric variable?  If you want to create a string use the STR3 value with period inserted before the last two characters.  If you want to create a numeric variable then use the INPUT() function with the 20.2 informat. 

OUTSTANDING_BAL_BAD = INPUT(OUTSTANDING_BAL,20.2)

That .2 means that SAS should assume the decimal point is before the last two characters, when there is not one in the string being read.  That is it divides such values but 10**2.

If the string OUTSTANDING_BAL can contain commas and dollar signs you could use COMMA20.2 informat instead.  Note that the DOLLAR informat is just an alias for the COMMA informat.

 

Kurt_Bremser
Super User

Both of your codes are an example for overcomplicating things, and how that ends with shooting oneself in the foot. The following leads to the exact same result, with a minimum of effort:

data PAY_FILE;
input OUTSTANDING_BAL $15.;
cards;
000000000120584
000000000005073
000000000008371
000000000001000
000000000081000
000000000009000
;

data PAY_FILE_want;
set PAY_FILE;
format OUTSTANDING_BAL_num dollar20.2;
OUTSTANDING_BAL_num = input(OUTSTANDING_BAL,15.2);
run;

See the first quote of Maxim 37.

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
  • 7 replies
  • 919 views
  • 1 like
  • 4 in conversation