【问题标题】:SAS lopping off a digit at the end of a decimal pointSAS 在小数点末尾删除一个数字
【发布时间】:2021-01-21 17:48:46
【问题描述】:

我正在尝试为每条记录添加一个具有相同值的变量。我创建了大约 10 个这样的变量(每个都有不同的值)。对于其中一个,SAS 没有保留最后一位数字 (1)。我尝试调整格式以使其更长,但不是添加 1,而是在右侧添加额外的零。

这里是代码示例:

data createnewvars;
  set original;
  
variable1=39.5652749413775;
variable2=0.359365098601411;

format variable1 17.13 variable2 18.15;
run;

当我查看数据时,variable2 的值 = 0.359365098601410。 仅供参考,当我缩短 variable2=0.3593650986014 的格式(例如 17.13)值时,这是意料之中的。

任何想法如何解决这个问题?

【问题讨论】:

标签: sas format


【解决方案1】:

第一:你的问题的实际答案;然后题外话是关于如何存储数字的,如果你有兴趣的话。

SAS 能够很好地存储您在上面显示的数字(或者,无论如何都足够好),但它对您隐藏了一点精度,基本上是为了表现得很好 - 以第 15 位小数进行数学运算很棘手,因为您在失去实际精度之前几乎没有空间。

但是,有一个选项可以让 SAS 表现出自己的行为并展示其全部功能。 DECIMALCONV 系统选项。默认情况下,它设置为 COMPAT,这与旧版本的 SAS 保持一致;但是,如果您将其设置为 STDIEEE,它将显示您上述号码的所有数字。它不会向您显示太多更多,请注意;你真的处于精度的极限。这是在SAS 9.4 中添加的,因此如果您的营业地点仍有 9.3 或更早版本,请不要使用它。该选项也可能被您的系统管理员锁定,因此如果您在服务器环境中并且发现该选项不允许或不起作用,请与他们联系。

查看这两个数据步骤的实际效果:

options decimalconv=compat;
data _null_;
  variable2=0.35936509860141;
  variable3=0.359365098601411;
  put variable2= best18. / variable3= best18.;
run;

 variable2=0.35936509860141
 variable3=0.35936509860141

options decimalconv=stdieee;
data _null_;
  variable2=0.35936509860141;
  variable3=0.359365098601411;
  put variable2= best18. / variable3= best18.;
run;


 variable2=0.35936509860141
 variable3=0.359365098601411

就像变魔术一样,variable3 现在会显示您要求的额外 1。不过,我怎么强调都不过分,这会影响变量中存储的内容;它只会影响它在屏幕上的显示方式(以及您在其他任何地方使用它的方式) - 它始终是相同的数字,它几乎但不完全是您想要的,就像大多数浮点数一样。它也处于精度的边缘,所以如果你用它做进一步的数学运算,“几乎但不完全”可能很重要。如果您需要这种更高的精度,SAS 可能不是您工作的理想语言。


现在,解释一下这里发生了什么。 SAS 能够存储精度高达 2^53 的数字,即几乎 16 位十进制数字的精度。但是,当您将鼠标悬停在精度限制之上时,SAS 往往不会显示那么整齐,因为与 2 的幂相关的舍入问题 - 因为数字以二进制形式存储,所以并非如此巧妙地存储一个精确的十进制数,就像在十进制中存储“1/3”是不可行的。但数字仍然存在,一切都一样。

在您的示例中,SAS 确实以不同方式存储这两个数字,尽管事实上它不会以不同方式显示它们。请参阅以下内容,从您的示例扩展:

data createnewvars;

  
variable1=39.5652749413775;
variable2=0.35936509860141;
variable3=0.359365098601411;

put variable2= best18. / variable3= best18.;
put variable2= hex16. / variable3= hex16.;
put variable2= binary64. / variable3= binary64.;

equal = variable2 - variable3;
run;

这会导致:

 variable2=0.35936509860141
 variable3=0.35936509860141
 variable2=3FD6FFD67874479F
 variable3=3FD6FFD6787447B1
 variable2=0011111111010110111111111101011001111000011101000100011110011111
 variable3=0011111111010110111111111101011001111000011101000100011110110001

请注意,最后的十六进制表示形式略有不同。这是尾数的结尾,或 SAS 存储的“精确”部分。 (顺便说一下,这是假设您在 Linux/Unix/Windows 上运行;在 IBM 大型机上,这会有所不同,但在高级概念上类似。)事实上,它相差大约 1x10 -15,当乘以两个适当的各种幂时 - 看看示例中的 equal,它非常接近这个数字 - 但我们稍后会谈到。

不同的部分是最后 6 位数字:011111 表示较短的数字,110001 表示较长的数字。这些数字分别乘以数字的符号部分定义的 2 的幂,在这两种情况下都是 01111111101 - 十进制数 1021,然后偏移 -1023,最终结果为 -2。这意味着第一个数字(二进制​​表示中的第 13 个数字)代表 2-3,下一个数字代表 2-4,依此类推。

那么,最后 6 位数字代表 2-49 到 2-54。二进制中的110001 - 011111010010,即 2-50 加上 2-53。这两个数字加在一起并转换为十进制是 9.99x10-16,或者与您忘记的 1x10-15 差不多。另外,还记得上面 SAS 代码中的 equal 变量吗?看一下日志——实际上是等价的。

那么 - 为什么 SAS 不能显示最后一位数字?这是因为它不完全等于最后一个 1 - 它的偏移量小于 SAS 可以干净存储的量(在您的示例中,小于 2-54)。因此,SAS 不想骗你说它能够安全准确地存储它,所以它对你隐瞒了真相。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    相关资源
    最近更新 更多