TPKアルゴリズム はドナルド・クヌース とルイス・トラブ・パルドがコンピュータのプログラミング言語 の進化を説明するために紹介した簡単なプログラムである。1976年 8月 の論文『プログラミング言語の初期開発』(原題 “The Early Development of Programming Languages ” [1] )の中で,配列 ,インデクス,数学的関数 ,サブルーチン ,入出力 ,条件分岐 と繰り返しに関する小さなプログラムを紹介した。次に初期のプログラミング言語でのアルゴリズムの実装を記してその概念がどう表現されるか説明した。
“TPK” の名前について,作者はグリムの法則 (ゲルマン語 の子音 /t/ , /p/ と/k/ に関する法則),“typical” という語の発音(IPA : [ˈtɪ.pɪ.k(ə)l]),および名前のイニシャル(T rabb P ardo と K nuth)に言及した。クヌースはその論文に基づいたトークで,以下のように述べた:
このテーマがいかに深いかは,人々がどれほどもがき,アイデア一つ一つがどのようにして生まれたのか考えければ理解できない。これを研究するために,—ルイスがこのアイデアの中心的な発案者だと思うが—我々はプログラム—あるいはアルゴリズム—を一つとって,すべての言語でそれをコードに書く。そうして,一つの例から,直ちにその特定の言語の特徴を分析できる。これをTPKプログラムと呼ぶが,これがTrabb PardoとKnuthのイニシャルになっているのはただの面白い偶然に過ぎない。
アルゴリズム
クヌースは以下のように説明する:
「TPKアルゴリズム」と呼ばれる簡単な手続きを導入し,各言語に対してそれぞれ独自のスタイルでプログラムを書くことで特徴を見出した。[…] TPKアルゴリズムは,11個の数
a
0
,
a
1
,
… … -->
,
a
10
{\displaystyle a_{0},a_{1},\ldots ,a_{10}}
を入力し,以下の定義によって11個の数の組
(
10
,
b
10
)
,
(
9
,
b
9
)
,
… … -->
,
(
0
,
b
0
)
,
{\displaystyle (10,b_{10}),(9,b_{9}),\ldots ,(0,b_{0}),}
を出力する。
定義:
b
i
=
{
f
(
a
i
)
,
if
f
(
a
i
)
≤ ≤ -->
400
;
999
,
if
f
(
a
i
)
>
400
;
{\displaystyle b_{i}={\begin{cases}f(a_{i}),&{\text{if }}f(a_{i})\leq 400;\\999,&{\text{if }}f(a_{i})>400;\end{cases}}}
ここに
f
(
x
)
=
|
x
|
+
5
x
3
{\displaystyle f(x)={\sqrt {|x|}}+5x^{3}}
この簡単な手続きは明らかにどのまとものコンピュータ言語でも大したことはない。
擬似言語:
ask for 11 numbers to be read into a sequence S
reverse sequence S
for each item in sequence S
call a function to do an operation
if result overflows
alert user
else
print result
このアルゴリズムは入力から11 の数を受け取って配列に格納し,逆順にしてから,ユーザー定義の関数を各数に適用して関数の返り値またはその値が閾値を超越した旨のメッセージを報告する。
実装
論文で説明された実装
初版の高水準プログラミング言語の開発の「だいたい最初の10年をカバーした」(1945年 から1957年 まで)論文では,ALGOL 60 が論文で実際に議論された言語より後の開発であることを注記した上で「ALGOL 60の方言」での実行の例を挙げた(以下)。
TPK : begin integer i ; real y ; real array a [ 0 : 10 ] ;
real procedure f ( t ) ; real t ; value t ;
f := sqrt ( abs ( t )) + 5 × t ↑ 3 ;
for i := 0 step 1 until 10 do read ( a [ i ]) ;
for i := 10 step - 1 until 0 do
begin y := f ( a [ i ]) ;
if y > 400 then write ( i , 'TOO LARGE' )
else write ( i , y ) ;
end
end TPK .
初期の高水準言語 の多くはTPKアルゴリズムを正確に処理できなかったため,以下の修正を認めた:
もしその言語が整数の変数にしか対応していないなら,すべての入力と出力が整数値関数済であり,sqrt(x)
が
x
{\displaystyle {\sqrt {x}}}
を超えない最大の「整数」を意味すると仮定する。
もしその言語がアルファベットの出力に対応していないなら,“TOO LARGE”(過剰)の文字列の代わりに999 を出力する。
もしその言語が入力と出力を一切 認めないなら,11の入力の値
a
0
,
a
1
,
… … -->
,
a
10
{\displaystyle a_{0},a_{1},\ldots ,a_{10}}
は何らかの方法で外部プロセスによって与えられたものと仮定し,タスクを22 の出力の値
10
,
f
(
10
)
,
9
,
f
(
9
)
,
… … -->
,
0
,
f
(
0
)
{\displaystyle 10,f(10),9,f(9),\ldots ,0,f(0)}
(ただし
f
(
i
)
{\displaystyle f(i)}
の値が大きすぎる場合は999に置換) を計算することと考える。
もしその言語が関数定義を認めないなら,f(a[i])
を定義式
|
a
i
|
+
5
a
i
3
{\displaystyle {\sqrt {|a_{i}|}}+5a_{i}^{3}}
で置換する。
必要ならこれらの修正を施し,作者らはこのアルゴリズムを以下で実装する:
コンラート・ツーゼ のプランカルキュール
ハーマン・ゴールドスタイン とジョン・フォン・ノイマン のフローチャート
ハスケル・カリー が提唱した記法
ジョン・モークリー らのShort Code
アーサー・バークス のIntermediate Program Language
ハインツ・ルティスハウザー の記法
コラド・ベーム の言語とコンパイラ(1951~52)
アリク・グレニーのAutocode
グレース・ホッパー のA-2 システム
Laning and Zierler system
ジョン・バッカス の最初に提唱されたフォートラン (1954)
トニー・ブルッカーによるAutocode for Mark 1
アンドレイ・エルショフのПП-2
Mandalay GremsとR. E. PorterによるBACAIC
A. Kenton ElsworthらのKompiler 2
E. K. BlumのADES
アラン・パリス のthe Internal Translator
ジョン・バッカスのフォートラン
グレース・ホッパーの研究室のARITH-MATICとMATH-MATIC
フリードリッヒ・L・バウアーとクラウス・サメルソンのシステム
(2003・2009追記)PACT I
TRANSCODE
そしてどのような演算が利用可能かの説明があり,これらの言語の「実装」,「可読性」,「制御構造」,「データ構造」,「機械独立性」と「インパクト」の観点からの主観評価,さらにそれぞれ最初にしたことが続く。
より最近の言語での実装
#include <math.h>
#include <stdio.h>
double f ( double t )
{
return sqrt ( fabs ( t )) + 5 * pow ( t , 3 );
}
int main ( void )
{
double a [ 11 ] = { 0 }, y ;
for ( int i = 0 ; i < 11 ; i ++ )
scanf ( "%lf" , & a [ i ]);
for ( int i = 10 ; i >= 0 ; i -- ) {
y = f ( a [ i ]);
if ( y > 400 )
printf ( "%d TOO LARGE \n " , i );
else
printf ( "%d %.16g \n " , i , y );
}
return 0 ;
}
from math import sqrt
def f ( t ):
return sqrt ( abs ( t )) + 5 * t ** 3
a = [ float ( input ()) for _ in range ( 11 )]
for i , t in reversed ( list ( enumerate ( a ))):
y = f ( t )
if y > 400 :
print ( i , "TOO LARGE" )
else :
print ( i , y )
use std ::{ io , iter ::zip };
fn f ( t : f64 ) -> f64 {
t . abs (). sqrt () + 5.0 * t . powi ( 3 )
}
fn main () {
let mut a = [ 0 f64 ; 11 ];
for ( t , input ) in zip ( & mut a , io ::stdin (). lines ()) {
* t = input . unwrap (). parse (). unwrap ();
}
a . iter (). enumerate (). rev (). for_each ( | ( i , & t ) | match f ( t ) {
y if y > 400.0 => println! ( "{i} TOO LARGE" ),
y => println! ( "{i} {y}" ),
});
}
外部リンク