为什么 binaryw.格式在宽度 58 以上表现不同?

Why does the binaryw. format behave differently above width 58?

考虑以下程序和输出:

data _null_;
input a;
length b ;
do i = 1 to 64;
  fmtname = cats('binary',i);
  b = cats(putn(a,fmtname));
  put i= b=;
end;
cards;
1
;
run;

输出(SAS 9.1.3,Windows 7 x64):

i=1 b=1
i=2 b=01
i=3 b=001
i=4 b=0001
i=5 b=00001
/*Skipped a few very similar lines*/
i=58 b=0000000000000000000000000000000000000000000000000000000001
i=59 b=11111110000000000000000000000000000000000000000000000000000
i=60 b=111111110000000000000000000000000000000000000000000000000000
i=61 b=1111111110000000000000000000000000000000000000000000000000000
i=62 b=11111111110000000000000000000000000000000000000000000000000000
i=63 b=011111111110000000000000000000000000000000000000000000000000000
i=64 b=0011111111110000000000000000000000000000000000000000000000000000

Linux x64 上 SAS 9.4 的最后几行输出:

 i=60 b=000000000000000000000000000000000000000000000000000000000001
 i=61 b=1111111110000000000000000000000000000000000000000000000000000
 i=62 b=11111111110000000000000000000000000000000000000000000000000000
 i=63 b=011111111110000000000000000000000000000000000000000000000000000
 i=64 b=0011111111110000000000000000000000000000000000000000000000000000

这种行为相当出乎意料,至少对我来说是这样,并且似乎没有记录在宽度为 64 的 help page. It agrees with the document I found here 上 - 标准双精度 - 但我不明白为什么它会翻转宽度 59.

我得到的结果不太一样 - 我的开关是 61 - 但我相信答案是一样的。

直到某个点 - 58、60 附近的某处 - SAS 向您展示了数字的 fixed-point 整数表示。用小数测试这个,像这样:

data _null_;
a=3.14159265358979323846264338327950288419716939937510582;
length b ;
put a= hex4.;
put a= hex8.;
put a= hex16.;
do i = 1 to 64;
  fmtname = cats('binary',i);
  b = cats(putn(a,fmtname));
  put i= b=;
end;
run;

你会得到一个 sort-of-surprising 结果 - 大多数行你会看到 000...0011,直到 60。文档没有明确提到这一点,但它确实在示例(123.45 和 123 在 binary8. 中相同)。

然后从 61 开始,或者我猜你是 59,你会看到数字的实际表示形式,因为 SAS 内部存储它(或者,可以说,英特尔内部存储它的方式)。

二进制文件没有很好地解释这一点,但是 HEX. 文件在提示中解释得非常清楚:

If w< 16, the HEXw. format converts real binary numbers to fixed-point integers before writing them as hexadecimal characters. It also writes negative numbers in two's complement notation, and right aligns digits. If w is 16, HEXw. displays floating-point values in their hexadecimal form.

二进制做同样的事情,在我的机器上它恰好发生在 HEX 也会进行更改的位置 - 在 15x4=60。并且 HEX. 显示相同 - 请注意以下内容; hex4.hex8. 显示的结果与 hex16. 不同。

明确地说,binary64. 处显示的值是正确的,没有任何形式的截断(尽管 61-63,在您的示例中是 59-60,是 left-truncated)。


我确实找到了一个关于此的 SAS usage note,尽管根据我们的测试它显然已经过时了:

Beginning with SAS® Version 7, the BINARYw. format was changed to be more consistent with the HEXw. format. When the HEXw. format uses a width of 16, (corresponding to 8 bytes of data), it produces a hexadecimal representation of the floating point value. The BINARYw. format changed so that widths of 57-64 produce a binary representation of the floating point value, since widths of 57-64 correspond to 8 bytes of data.

它还包含有关如何为整数获得一致结果的建议,可能会有用。

BIN_64=PUT(PUT(VALUE,S370FIB8.),$BINARY64.);

S370FIB8. 是一个 format,它将数字转换为 IBM 大型机格式的固定整数二进制表示形式。 (即,它以 Big-Endian 格式写入整数,这不是您在 Intel 机器上获得的格式。)