2

I'm trying to determine how SAS is reading the length statement and then the informat statement. I could be misunderstanding, but I'm under the impression that the informat statement for numeric variables worked like this:

informat number 5.;

This would give the variable number the informat 5, allowing 5 numbers to fill it. E.G. 12345

However, when I run the below program, I have a number that has 9 digits, 987654321, with the appropriate length to fit the digits, 6, which will represent all numbers up to 137,438,953,472

Q: is length statement 'overriding' the informat statement and allowing all 9 digits to fill the variable number? How are all 9 digits able to fit in the variable number with an informat of 5.?

data tst;
input number;
length number 6;
informat number 5.;
datalines;
987654321
;
run;

proc print data=tst;
run;

Based on this SAS documentation: http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000199348.htm

w specifies the width of the input field. Range: 1-32

It would seem that the informat w.d would work as I first described and not allow all 9 digits to fill number

DukeLuke
  • 315
  • 6
  • 26
  • 1
    Hi - this is a great question, thanks for asking it and providing such specific detail in the question. Questions like this are a pleasure to answer! – Joe May 16 '18 at 16:48
  • @Joe No problem. I've genuinely been confused by this. In the past I've had no issue using informats because I would have done `informat number 9.` with the appropriate length. I came across this and was stumped. To my disbelief the output data has been correct. – DukeLuke May 16 '18 at 17:05

3 Answers3

2

Because you are using list mode input. In that situation SAS reads the next word, however long it is. Essentially in list mode input (including when using the : modifier before an informat specified in the input statement) the width on a informat is ignored.

Other than for creating metadata in the SAS dataset there is not much value in attaching informats like 5. or $10. to variables.

  • SAS does not need them to understand how to convert text into values, unlike informats like date..
  • In list mode it ignores the width part.
  • And in formatted input, where the width matters, you have to specify the informat in the INPUT statement itself.
Tom
  • 47,574
  • 2
  • 16
  • 29
  • Do you mean specific the *informat* in the input statement itself? – DukeLuke May 16 '18 at 20:06
  • Also, it's safe to say that list input will read a character variable without an informat (or length statement) up until length 8? – DukeLuke May 16 '18 at 20:10
  • @DukeLuke List input ignores the informat for width purposes, unless it's creating the variable in which case the informat defines length. It will read up to the defined length, or 8 if never previously defined. – Joe May 16 '18 at 20:13
  • The original question was for the case when the variable's type and length had already been defined. The side effect of how SAS guesses at what type and length to use if the first reference to a variable includes an informat specification can be covered in a different question. – Tom May 16 '18 at 23:07
1

The length of a variable defines the amount of space the value occupies when stored to disk. NOTE: During a running DATA step all numerics are double precision, the truncation to a length < 8 only occurs during output media.

The informat is a separate concept from the length. Informat defines how incoming value representations are to be interpreted for storage as a SAS numeric value. Incoming value representations would be what ever text has to be processed; be it a INPUT statement reading a file, a VIEWTABLE field edit processing a typed in value, an EG grid cell edit, etc...

The format is similarly separate concept that defines how SAS renders a numeric value for output; be it a PUT statement, a VIEWTABLE row render, a placement in a PROCs output, an EG grid cell, etc...

Explanation

Now that that is out of the way, The informat is honored when explicitly stated in an INPUT statement:

data _null_;
  attrib number length=6 informat=5.;
  input number 5.;
  put 'NOTE: ' number=;
  datalines;
987654321
run;
===== LOG ===== 
NOTE: number=98765

And, as you question, the variables associated informat is not applied an explicit numeric informat is not stated

data _null_;
  attrib number length=6 informat=5.;
  input number;
  put 'NOTE: ' number=;
datalines;
987654321
run;
===== LOG =====
NOTE: number=987654321

So the first is LIST input with format specified and the second is a simple LIST input (because no format is specified).

Simple list input will accept some absurdly large data, and the resultant value, while not tail-end precise, will be at the correct exponential level.

data _null_;
  attrib number length=6 informat=5.;
  input number;
  put 'NOTE: ' number= ;
datalines;
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
run;
===== LOG =====
NOTE: number=1.2345679E89

What do the docs for INPUT Statement, List say ? Certainly nothing about using the variables declared informat when none indicated

Simple List Input

Simple list input places several restrictions on the type of data that the INPUT statement can read:

• By default, at least one blank must separate the input values. Use the DLM= or DLMSTR= option or the DSD option in the INFILE statement to specify a delimiter other than a blank.

• Represent each missing value with a period, not a blank, or two adjacent delimiters.

• Character input values cannot be longer than 8 bytes unless the variable is given a longer length in an earlier LENGTH, ATTRIB, or INFORMAT statement.

• Character values cannot contain embedded blanks unless you change the delimiter.

• Data must be in standard numeric or character format. (footnote 1)

FOOTNOTE 1: See SAS Language Reference: Concepts for the information about standard and nonstandard data values. (my LOL)

The concepts for "SAS Variable Attributes" states

informat

refers to the instructions that SAS uses when reading data values. If no informat is specified, the default informat is w.d for a numeric variable, and $w. for a character variable. You can assign SAS informats to a variable in the INFORMAT or ATTRIB statement. You can use the FORMAT procedure to create your own informat for a variable.

(my bold)

Apparently there is no explicit default such as 32. or best32. because values with more than 32 digits will be inputted without error.

So does the documentation explain things ? Yea, well, sorta. What are the take aways:

  • The human intuition of a numeric variable inheriting its informat during simple list input does not align with the actual implemented behavior.
    • Tectonic amounts of existing SAS code means a change to implement this intuition is highly unlikely
  • Simple statements can involve a lot of concepts with wide ranging documentation
  • Possible change is that the documentation will be updated to be more explicit about the simple list input caveats
Richard
  • 25,390
  • 3
  • 25
  • 38
1

First off: length is not overriding, or having any impact on, the informat or the read-in. length solely describes how many bytes are used to store the number, nothing more.

For numeric variables, informats don't work quite the intuitive way. I'm not sure why - but they don't.

See this quotation from the list input documentation:

For a character variable, this format modifier reads the value from the next non-blank column until the pointer reaches the next blank column, the defined length of the variable, or the end of the data line, whichever comes first. For a numeric variable, this format modifier reads the value from the next non-blank column until the pointer reaches the next blank column or the end of the data line, whichever comes first.

They do listen to the informat to some extent - add a .2 there and you'll get a forced decimal - but they don't listen to it as to how long of a value to read in. I'm not sure why; it seems intuitive that they should, but they don't.

Here's it with character variables - they respect the length but also ignore the informat:

data tst;
length number $9;
informat number $5.;
input number;
datalines;
987654321
;
run;

proc print data=tst;
run;

Though you do need to put the informat before the input statement (and the length for numeric variables).

More detail is available on the documentation page for INFORMAT:

How SAS Treats Variables When You Assign Informats with the INFORMAT Statement

Informats that are associated with variables by using the INFORMAT statement behave like informats that are used with modified list input. SAS reads the variables by using the scanning feature of list input, but applies the informat.

In modified list input, SAS does not use the value of w in an informat to specify column positions or input field widths in an external file uses the value of w in an informat to specify the length of previously undefined character variables ignores the value of w in numeric informats uses the value of d in an informat in the same way it usually does for numeric informats treats blanks that are embedded as input data as delimiters unless you change their status with a DLM= or DLMSTR= option specification in an INFILE statement.

That is much more explicit about the fact that SAS ignores the value of w.

Joe
  • 62,789
  • 6
  • 49
  • 67
  • SAS does not treat numbers and characters differently. I think the confusion is in the fact that if the target character variable is too short then only the number of bytes that fit are stored and the rest are basically ignored. That is the cursor moves past the next delimiter. – Tom May 16 '18 at 17:49
  • @Tom Yes, thanks, I meant to remove that once I'd read the rest of the information and forgot to - fixed! – Joe May 16 '18 at 18:09