TPKアルゴリズムは、ドナルド・クヌースとルイス・トラブ・パルドがコンピュータプログラミング言語の進化を説明するために考案したシンプルなプログラムです。1977年に出版された彼らの著書『プログラミング言語の初期開発』の中で、トラブ・パルドとクヌースは、配列、インデックス、数学関数、サブルーチン、入出力、条件分岐、反復処理を含む小さなプログラムを紹介しました。そして、これらの概念がどのように表現されるかを示すために、初期のプログラミング言語でこのアルゴリズムの実装を作成しました。
「TPK」という名前を説明するために、著者らはグリムの法則(子音「t」、「p」、「k」に関するもの)、「typical」という単語の音、そして自分たちのイニシャル(Trabb PardoとKnuth)に言及した。[ 1 ]この論文に基づいた講演で、Knuthは次のように述べた。[ 2 ]
このテーマの奥深さを理解するには、優秀な人々がいかに苦労して取り組んできたか、そしてアイデアが一つずつどのように生まれてきたかを知る必要があります。この研究のために――このアイデアの主な発案者はルイスだったと思いますが――私たちは一つのプログラム、つまり一つのアルゴリズムを取り上げ、それをあらゆる言語で記述します。そうすることで、一つの例からその言語特有の特性を素早く把握できるのです。私たちはこれをTPKプログラムと呼んでいますが、それがトラブ・パルドとクヌースの頭文字をとったものであることは、単なる面白い偶然です。
クヌースはそれを次のように説明しています。[ 3 ]
私たちは「TPKアルゴリズム」と呼ばれるシンプルな手順を導入し、それぞれの言語特有のスタイルでTPKを表現することで、各言語の個性を表現しました。[…] TPKアルゴリズムは11個の数値を入力として受け取ります。すると、11組のペアのシーケンスが出力されます。どこ
この単純な作業は、まともなプログラミング言語であれば、明らかにそれほど難しいものではない。
擬似コードでは:
11個の数値をシーケンスS に読み込むように要求する。シーケンスSを逆順にする。シーケンスSの各項目に対して関数を呼び出して操作を実行する。 結果がオーバーフローした 場合はユーザー に警告する。そうでない場合は結果を表示する。
このアルゴリズムは、入力デバイスから11個の数値を読み込み、配列に格納した後、逆順に処理します。各値にユーザー定義関数を適用し、関数の値、または値が一定の閾値を超えたことを示すメッセージを報告します。
元の論文では、高水準プログラミング言語の開発の「おおよそ最初の 10 年間」(1945 年~ 1957 年)を扱っており、ALGOL 60の方言での以下の実装例を示し、ALGOL 60 は実際に論文で議論されている言語よりも後に開発されたものであると指摘している。[ 1 ]
TPK : begin integer i ; real y ; real array a [ 0 : 10 ] ;実数手順f ( t ) ;実数t ;値t ;f := sqrt ( abs ( t )) + 5 × t ↑ 3 ;for i := 0 step 1 until 10 do read ( a [ i ]) ;iが10 になるまでステップ- 1を繰り返して0 になるまで繰り返すbegin y := f ( a [ i ]) ;y > 400の場合、( i , '大きすぎます' )と書き込むそうでなければ、( i , y )と書きます。終わりTPK を終了します。初期の高級言語の多くは TPK アルゴリズムを正確に処理できなかったため、以下の変更が可能でした: [ 1 ]
sqrt(x)最大整数は。'TOO LARGE'数値999を出力します。f(a[i])次の式に置き換えてください。。必要に応じてこれらの修正を加えた上で、著者らはこのアルゴリズムをコンラート・ツーゼのプランカルクル、ゴールドスタインとフォン・ノイマンのフロー図、ハスケル・カリーの提案記法、ジョン・モークリーらのショートコード、アーサー・バークスの中間プログラム言語、ハインツ・ルティシャウザーの記法、 1951~52年のコラード・ベームの言語とコンパイラ、アリック・グレニーのオートコード、グレース・ホッパーのA-2システム、ラニングとツィーラーのシステム、ジョン・バッカスが最初に提案したFortran(1954年)、トニー・ブルッカーのMark 1用オートコード、アンドレイ・エルショフのПП-2 、マンダレー・グレムスとREポーターのBACAIC、A・ケントン・エルズワースらのKompiler 2、EKのADESに実装している。 Blum、 Alan Perlisの内部翻訳、John Backus のFortran 、 Grace Hopperの研究室のARITH-MATICとMATH-MATIC 、 BauerとSamelsonのシステム、そして (2003 年と 2009 年の補遺で) PACT I と TRANSCODE について説明されています。次に、どのような算術が利用可能であったかを説明し、「実装」、「可読性」、「制御構造」、「データ構造」、「マシン独立性」、「影響」のパラメータに基づいてこれらの言語を主観的に評価し、それぞれが最初に行ったことについても言及しています。[ 1 ]
これは、上記のALGOL 60と同等のC言語による実装例を示しています。
#include <math.h>#include <stdio.h>ダブルf (ダブル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 a [私]);for ( int i = 10 ; i >= 0 ; i -- ) {y = f ( a [ i ]);if ( y > 400 )printf ( "%d は大きすぎます\n " , i );それ以外printf ( "%d %.16g \n " , i , y );}}これはPythonによる実装例です。
from math import sqrtdef f ( t ):return sqrt ( abs ( t )) + 5 * t ** 3a = [ float ( input ()) for _ in range ( 11 )]for i , t in reversed ( list ( enumerate ( a ))):y = f ( t )print ( i , "大きすぎます" if y > 400 else y )これはJavaによる実装例です。
import java.util.Arrays ;import java.util.ArrayList ;import java.util.Collections ;import java.util.List ;import java.util.Scanner ;public class TPKAlgorithm {// ユーザー定義関数private static double f ( double x ) {return Math.sqrt ( Math.abs ( x ) ) + 5 * Math.pow ( x , 3 ) ;}public static void main ( String [] args ) {// ユーザー入力用のScannerオブジェクトを作成しますScanner scanner = new Scanner ( System.in ) ;// 入力された数値を格納するためのArrayListを作成しますList < Double > inputNumbers = new ArrayList <> ();System.out.println ( "11個の数字を入力してください: " ) ;int inputNumber ;// ユーザー入力から11個の数字を取得するfor ( int i = 1 ; i <= 11 ; i ++ ) {if ( scanner.hasNextDouble ( ) ) {inputNumber = scanner.nextDouble ( ) ;inputNumbers 。追加( inputNumber );}}スキャナーを閉じる// アルゴリズムロジックCollections.reverse ( inputNumbers ) ;for ( int n = 0 ; n < inputNumbers . size (); n ++ ) {int i = inputNumbers.size ( ) - ( n + 1 ) ;double y = f ( inputNumbers . get ( n ));if ( y > 400 ) {System.out.printf ( "% d TOO LARGE %n " , i ) ;}それ以外{System.out.printf ( " % d % .2f %n" , i , y ) ;}}}}これはRustによる実装例です。
use std ::{ io , iter };fn f ( t : f64 ) -> Option < f64 > {y = tとします。腹筋()。sqrt () + 5.0 * t 。ポウイ( 3 );( y <= 400.0 ). then_some ( y )}fn main () {let mut a = [ 0 f64 ; 11 ];for ( t , input ) in iter :: zip ( & mut a , io :: stdin (). lines ()) {* t = input.unwrap (). parse ( ). unwrap ( );}a.iter ( ). enumerate (). rev ( ). for_each ( | ( i , & t ) | match f ( t ) {None => println! ( "{i} は大きすぎます" ),Some ( y ) => println! ( "{i} {y}" ),});}