Unix V5とV6のsum
コマンドがどのアルゴリズムを使用しているのかわかりません。
最初は2^16モジュロバイトの単純な和だと思いました。ただし、320回繰り返される文字列 "1111111111\n"の場合、計算されるチェックサムは次のようになります。28930(使用Julius SchmidtのPDP-11エミュレータJavaScriptの場合)。そして、単純バイト合計は2バイト少ないです。
$ python -c 'print(sum(bytearray(b"1111111111\n"*320)) & 0xFFFF)'
28928
後で、MacOS のマニュアルページsum
、長い間コマンドにcksum
矛盾があることがわかりました。ただし、MacOSで利用可能なアルゴリズムの「過去」バージョンもUnix V5チェックサムと一致しません。最も近い一致はsum
UNIX System Vの基本コマンド(Macで呼び出されるなどcksum -o 2
)で、この文字列に対して同じチェックサムを返しますが、他のコマンドとは一致しません。
$ python -c 'print("1111111111\n"*320, end="")' | cksum -o 2
28930 7
具体的には、cksum -o 2
Unix V5とUnix V5はほとんどのテキストファイルでは一貫性がありますが、sum
エミュレータ(フォルダ内など)でほとんどのバイナリファイルに対して異なる出力を生成します。/bin
これは実際の動作ですか、それともエミュレータのバグですか?本当なら、アルゴリズムは何ですか?
PS:これソースコード誰もが1974年にアセンブリコードを読むことができれば。
答え1
最初は2^16モジュロバイトの単純な和だと思いました。
合計モードは2^16で、オーバーフローするたびに1ずつ増加します。さらに、バイトは合計に追加される前に符号拡張されます。以下はアセンブリの「コメント」の断片です。
# r2 is the pointer into the data
# r0 is the length of the data
# r5 is the sum
2:
movb (r2)+,r4 # r4 = sign_extend(*r2++)
add r4,r5 # r5 += r4
adc r5 # if(r5 overflowed) r5++
sob r0,2b # if(--r0) goto 2 above
同じ内容を小さなCプログラムに入れる(asを使用./v5sum < file
):
#include <stdio.h>
int main(void){
int c, s = 0;
while((c = getchar()) != EOF){
s += c & 0x80 ? c | 0xff00 : c; // alternative: s += (unsigned short)(signed char)c
if(s & 0x10000){ s++; s &= 0xffff; };
}
printf("%d\n", s);
return 0;
}
具体的には、cksum -o 2とUnix V5のsumはほとんどのテキストファイルで一貫していますが、エミュレータ(/ binフォルダなど)のほとんどのバイナリに対して異なる出力を生成します。
これは、元のUnix v5のsum
符号拡張文字とバイナリファイルにのみ0x80より大きいバイトが含まれているためです。そうでない場合、アルゴリズムは似ている必要があり、非常に大きなファイルでのみ異なります(文字合計は32ビット符号なし整数をオーバーフローします)。