总结后SAS错误总和

时间:2015-11-11 10:33:22

标签: sql sas zos

我有一个包含575965行的表。 “Ergebnisdaten”栏的格式为20.2

如果我提交以下内容:

 proc sql noprint;
  create table test as 
  select 
    Ergebnisdaten, 
    Ergebnisdaten*100 as euro format 20.4, 
    Ergebnisdaten*10000 as erg format 32.4,
    floor(Ergebnisdaten*10000) as floor format 20.4,
  floor(Ergebnisdaten*100)/100 as floor2 format 20.4
  from &source_lib..&source_table.;
quit;

proc sql noprint;
  select 
    sum(Ergebnisdaten) format=32.4, 
    sum(euro) format=32.4, 
    sum(erg) format=32.4, 
    sum(floor) format=32.4,
    sum(floor2) format=32.4
    into :sum_ges, :sum_euro, :sum_erg, :sum_floor, :sum_floor2
    from test;
 quit;

 %put Summe: &sum_ges.;  
 %put Summe: &sum_euro.;  
 %put Summe: &sum_erg.;  
 %put Summe: &sum_floor.;  
 %put Summe: &sum_floor2.;  

我得到5个不同的值:

380   %put Summe: &sum_ges.;

Summe:                 24507249859.0368

381   %put Summe: &sum_euro.;

Summe:               2450724985904.0000

382   %put Summe: &sum_erg.;

Summe:             245072498590400.0000

383   %put Summe: &sum_floor.;

Summe:             245072498562056.0000

384   %put Summe: &sum_floor2.;

Summe:                 24507249656.2654
  1. 如何在格式20.4中对表格求和并获得正确的值(24507249859.04)?

  2. 如果我启动相同的程序o zOS我得到24507249858.98。如何获得与Win / Unix上计算的值相同的值?

3 个答案:

答案 0 :(得分:2)

在没有看到实际数据的情况下,可能无法确定,但我的感觉是你遇到浮点数的数字精度问题。

由于数字在计算机上以二进制形式存储,因此在二进制文件中不能完美表示的任何内容都可能导致较小由于基数10(十进制)有2和5作为因子,而二进制只有2,你可以看到你不能完美地代表事物。

例如,在十进制中,分数1/3不能完全表示:

0.33333333333333

这是一个特别增加数字的问题,因为你要求SAS在上面做。例如:

1/3 + 1/3 + 1/3 = 1

.33333333333333 + .33333333333333 + .33333333333333 = .99999999999999

假设您的存储空间有限,哪些计算机可以。

通常,这不是问题。计算机的存储空间也有限,这往往意味着您可以在大多数情况下获得正确的答案。但是 - 并不是所有的时间。

由于您在两个字节(双)浮点数中可能达到最大精度,因此更加复杂。正如所讨论的here,您可以看到IEEE系统(Unix,Windows)上的最大浮点数将是52位 - 大约4 * 10 ^ 15 - 16位数。你接近这一点,这意味着计算机假装一个整数的通常的舍入/模糊事实实际上是一个整数(它不常,通常)不会像你想要的那样工作,因为你几乎使用了整个两个字节。

这也是你可能遇到格式问题的原因。你看到浮点不准确的一点点 - 因为你需要所有这些数字。通常使用BEST12。或BEST8。将隐藏所有这些混乱,但32.4或20.2显示完整的浮点数(超过12的任何东西可能会有一些问题,真的)。

至于你如何处理它 - 好吧,你可能无法做到。只要圆形数字可以或多或少地完全存储,圆形就可以在视觉上固定它。您的实际号码可以,如果这有用的话。使用round(x,.01)来获得您认为的应该是 - 但要明白这可能是不对的。

当然,你在这里问的问题是,为什么* 100显示04.00而不是* 100显示.0368?

见:

data hex;
  exactN = 24507249859.04;
  almost = 24507249859.0368;
  integr = 2450724985904;
  put exactN= 32.4;
  put almost= 32.4;
  put integr= 32.4;
  put exactN= hex16.;
  put almost= hex16.;
  put integr= hex16.;

run;

记录如下。前3个是正常显示的数字,第3个是它们存储在计算机中的方式(以十六进制而不是二进制显示)。

exactN=24507249859.0400
almost=24507249859.0368
integr=2450724985904.0000
exactN=4216D2FBD30C28F6
almost=4216D2FBD30C25AF
integr=4281D4D4BCE18000

请注意,exactN几乎以十六进制表示形式关闭 - 正如您所期望的那样,最后三位数都是关闭的,因为差异接近精度的边缘(当然这是小端)。但* 100完全不同。这是因为这是二进制的,所以你乘以100的事实对计算机来说并不是很有趣:存储完全不同,因为这是2的幂。如果你乘以128,你会有一个非常相似的十六进制字符串(但左侧稍微改变了),但是100结尾有一个完全不同的数字 - 意味着这个小浮点不准确性对于这个值是完全不同的,你最终会得到0400而不是0368 at结束。

答案 1 :(得分:0)

通过询问格式20.4,您告诉SAS您希望小数点后的4位精度。如果你想要小数点后的.04并使用20.4格式化,你需要将它舍入。

答案 2 :(得分:0)

你不能放:

Ergebnisdaten * 10000格式20.0进入测试 然后在test1表中重复整个过程,再次使用格式20.4决定10000。

所以首先将它放入一个表中,丢失数字,然后将其放入下一个数字中。