Community deutschsprachiger SAS-Anwender und -Programmierer

Antworten
Dies ist eine offene Gruppe. Melden Sie sich an und klicken Sie auf die Schaltfläche „Gruppe beitreten“, um Mitglied zu werden und damit zu beginnen, Beiträge in dieser Gruppe zu veröffentlichen.
Highlighted
SAS Employee
Beiträge: 232
Wie 'versteckte' Nachkommastellen von anzeigen/erkennen?
Hallo,
ich habe folgendes Problem, das sich um die Speicherung der Nachkommastellen in SAS dreht. Dabei ist die Frage etwas anders gelagert, als die der anderen Forumsbeiträge zu diesem Thema.
In folgendem Code wird nur die Variable vitdk4 korrekt mit 1 belegt, wenn der SICHTBARE (angezeigte) Inhalt der Variable vitd=24.4 ist. Es ist klar, dass mit einer vorhergehenden Rundung auf eine sinnvolle Anzahl von Nachkommastellen dieser Vergleich korrekt funktionieren würde.
Unsere Frage ist aber, wie man erkennen kann, ob SAS eine Dezimalzahl mit verborgenen Nachkommastellen gespeichert hat. Auch bei der auf 32-stellen formatierten Ausgabe des Variableninhalts war keine Nachkommastelle > 0 zu sehen. Bedeutet dies, dass man vor jeder Analyse seiner Daten ALLE numerischen Werte mit Dezimalstellen runden MUSS?
Vielen herzlichen Dank für erhellende Antworten,

data test;

set datei;

vitdk3=0; vitdk4=0; vitdk5=0;

if vitd=24.4 then vitdk3=1;

if round(vitd,0.00000000000001)=24.4 then vitdk4=1;

if round(vitd,0.000000000000001)=24.4 then vitdk5=1;

* vitdk4 hat als einzige Kategoriale Variable korrekten Inhhalt:;

if vitdk4=1 then do

   format vitd 32.29;

   put vitd= ;

   end;

* Ausgabe im LOG:
VITD=24.40000000000000000000000000000
;

run;

Learner
Beiträge: 0
Re: Wie 'versteckte' Nachkommastellen von anzeigen/erkennen?

Hi,

I don't have your original 'datei' table so I made some up in my 'datei' step.
If you take the FORMAT 32.29 away the displayed values are 'displayed as rounded'
but the internal value is unchanged.

In the 'datei' step:
The first thing to note is that decimal precision problems are being encountered:
Input value 24.3999999999999 (13 decimal places ) and input values 24.39999999999999
(14 decimal places) are both displayed as 24.3999999999999 with 13 places!

The effect is demonstrated again with 0.00...1 vs 0.09...1 (converts to 0.089...)

In the 'test' step we see the following effects:

  • 24.4 sets the flag vtdk* to 1 for all values (as per your original example)
  • 23.39.. (decimal 13 places) sets vtdk4a to 1 but not vtdk4b.
  • 23.39.. (decimal 14 places but only 13 displayed) sets vtdk4a and vtdk4b to 1!

SAS cannot display  the 14 decimal places correctly but internally the value is closer to 14 decimal places and the round function still works!  

The decision to round before every analysis will probably be based on the following factors:
1) data content / type of data
2) business area (rules and conventions)
3) desired outcome

All of which will be influenced or overridden by the precision of SAS 8 byte numeric data!


There are many SAS Papers on the subject of precision. One solution is to multiply decimals
to whole numbers for calculation (whole number precsion is superior to decimal places) and then divide the
end result. There is also a paper to implement a JAVA class
(http://www2.sas.com/proceedings/forum2008/021-2008.pdf) in order to use 'BigDecimal'.

Finally to answer your question:
SAS always uses the internal value for calculation. The round function, when applied appropriately, will
influence the calculation which can compensate for discrepancies between the displayed value and the
internally held value.

The round function will not rescue the situation where the internally held value has been
altered (corrupted) due to 8 byte precision issues.

Best Regards, Viele Grüße,
Ian

Sample Code and Data:

data datei;
/* Numeric Precision effects using SAS 9.3 on Windows 7 (64bit) - other Operating Systems may

display different values */ 
format vitd 32.29;
vitd = 24.4 ; OUTPUT;
put vitd ;
vitd = 24.3 ; OUTPUT;
put vitd ;
vitd = 24.3999999999999 ; OUTPUT;
put vitd ;
vitd = 24.39999999999999 ; OUTPUT;
put vitd ;
vitd = 24.5 ; OUTPUT;
put vitd ;
vitd = 1.00000000000000000000000000001 ; OUTPUT;
put vitd ;
vitd = 0.00000000000000000000000000001 ; OUTPUT;
put vitd ;
vitd = 0.09000000000000000000000000001 ; OUTPUT;
put vitd ;
run ;

data test;
set datei;
format vitd 32.29;
vitdk3=0; vitdk4a=0; vitdk4b=0; vitdk4c=0; vitdk5=0;

if vitd=24.4 then vitdk3=1;
/* 12 places */
if round(vitd,0.000000000001)=24.4 then vitdk4a=1;
/* 13 places */
if round(vitd,0.0000000000001)=24.4 then vitdk4b=1;
/* 14 places */
if round(vitd,0.00000000000001)=24.4 then vitdk4c=1;
/* 15 places */
if round(vitd,0.000000000000001)=24.4 then vitdk5=1;
* vitdk4 hat als einzige Kategoriale Variable korrekten Inhhalt:;
  if vitdk4a=1 then do; 
   put vitd= ;
  end;
  if vitdk4b=1 then do; 
    put vitd= ;
  end;
  if vitdk4c=1 then do; 
    put vitd= ;
  end;
run;

Respected Advisor
Beiträge: 3.823
Re: Wie 'versteckte' Nachkommastellen von anzeigen/erkennen?

There are no hidden decimals in SAS. You've got 8 bytes to store a number and you can see every single bit of it. 8 bytes give you full precision for 15 digits.

Use format "best32." (best16. would do actually).

data _null_;

  i=1;

  format var best32.;

  do while(i<1000000);

    var=i/3;

    put var=;

    i=i*10;

  end;

  stop;

run;

You get often issues with precision when moving floating point values between systems - eg. between SAS and a data base. It's a good idea to round the values there before any comparison.

For your case where it's about re-coding: You could also create a format (Proc Format) with a fuzz factor and then simply apply the format "new_val=put(old_val,myfmt.);