Algoritmo TPK - TPK algorithm

O algoritmo TPK é um programa simples apresentado por Donald Knuth e Luis Trabb Pardo para ilustrar a evolução das linguagens de programação de computador . Em seu trabalho de 1977 "O Desenvolvimento Inicial das Linguagens de Programação", Trabb Pardo e Knuth introduziram um pequeno programa que envolvia matrizes , indexação, funções matemáticas , sub-rotinas , E / S , condicionais e iteração . Eles então escreveram implementações do algoritmo em várias linguagens de programação antigas para mostrar como tais conceitos eram expressos.

Para explicar o nome "TPK", os autores se referiram à lei de Grimm (que diz respeito às consoantes 't', 'p' e 'k'), aos sons da palavra "típico" e às suas próprias iniciais (Trabb Pardo e Knuth). Em uma palestra baseada no jornal, Knuth disse:

Você só pode avaliar a profundidade do assunto vendo como boas pessoas lutaram contra ele e como as ideias surgiram uma de cada vez. Para estudar isso - acho que Luis foi o principal instigador dessa ideia - pegamos um programa - um algoritmo - e o escrevemos em todas as linguagens. E dessa forma, a partir de um exemplo, podemos rapidamente descobrir o sabor dessa linguagem em particular. Chamamos isso de programa TPK, e bem, o fato de ter as iniciais de Trabb Pardo e Knuth é apenas uma coincidência engraçada.

O algoritmo

Knuth o descreve da seguinte maneira:

Introduzimos um procedimento simples chamado “algoritmo TPK” e demos o sabor de cada linguagem, expressando o TPK em cada estilo particular. […] O algoritmo TPK insere onze números ; em seguida, ele produz uma sequência de onze pares onde

Esta tarefa simples obviamente não é um grande desafio, em qualquer linguagem de computador decente.

Em pseudocódigo:

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

O algoritmo lê onze números de um dispositivo de entrada, armazena-os em uma matriz e, em seguida, os processa na ordem inversa, aplicando uma função definida pelo usuário a cada valor e relatando o valor da função ou uma mensagem informando que o valor excedeu algum limite.

Implementações

Implementações no artigo original

No artigo original, que cobriu "aproximadamente a primeira década" do desenvolvimento de linguagens de programação de alto nível (de 1945 a 1957), eles deram o seguinte exemplo de implementação "em um dialeto do ALGOL 60 ", observando que o ALGOL 60 foi um desenvolvimento posterior às linguagens realmente discutidas no artigo:

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.

Como muitas das primeiras linguagens de alto nível não conseguiam lidar com o algoritmo TPK exatamente, elas permitem as seguintes modificações:

  • Se a linguagem suportar apenas variáveis ​​inteiras, então suponha que todas as entradas e saídas tenham valores inteiros, e isso sqrt(x)significa que o maior inteiro não excede .
  • Se o idioma não suportar saída alfabética, em vez da string 'TOO LARGE', imprima o número 999.
  • Se a linguagem não permite nenhuma entrada e saída, então suponha que os 11 valores de entrada foram fornecidos por um processo externo de alguma forma, e a tarefa é calcular os 22 valores de saída (com 999 substituindo valores muito grandes de ).
  • Se a linguagem não permitir que os programadores definam suas próprias funções, substitua f(a[i])por uma expressão equivalente a .

Com estas modificações quando necessário, os autores implementar este algoritmo em Konrad Zuse 's Plankalkül , em Goldstine e von Neumann ' s diagramas de fluxo , em Haskell Curry notação proposta 's, no código curto de John Mauchly e outros, no Intermediate Language Program de Arthur Burks , na notação de Heinz Rutishauser , na linguagem e compilador de Corrado Böhm em 1951-1952, no Autocode de Alick Glennie , no sistema A-2 de Grace Hopper , no sistema Laning e Zierler , nos primeiros proposto Fortran (1954) de John Backus , no Autocode para Mark 1 de Tony Brooker , em ПП-2 de Andrey Ershov , em BACAIC de Mandalay Grems e RE Porter, em Kompiler 2 de A. Kenton Elsworth e outros, em ADES de EK Blum, o tradutor interno de Alan Perlis , em Fortran de John Backus, em ARITH-MATIC e MATH-MATIC do laboratório de Grace Hopper , no sistema de Bauer e Samelson , e (em adendos em 2003 e 2009) PACT I e TRANSCODE. Em seguida, descrevem que tipo de aritmética estava disponível e fornecem uma avaliação subjetiva dessas linguagens sobre os parâmetros de "implementação", "legibilidade", "estruturas de controle", "estruturas de dados", "independência da máquina" e "impacto", além de mencionar o que cada um foi o primeiro a fazer.

Implementações em idiomas mais recentes

Implementação C

Isso mostra uma implementação C equivalente ao ALGOL 60 acima.

#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);
    }
}

Implementação Python

Isso mostra uma implementação Python.

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)

Implementação de ferrugem

Isso mostra uma implementação Rust.

use std::io::{self, prelude::*};

fn f(t: f64) -> f64 {
    t.abs().sqrt() + 5.0 * t.powi(3)
}

fn main() {
    let mut a = [0f64; 11];
    for (t, input) in a.iter_mut().zip(io::stdin().lock().lines()) {
        *t = input.unwrap().parse().unwrap();
    }

    a.iter().enumerate().rev().for_each(|(i, &t)| match f(t) {
        y if y > 400.0 => println!("{} TOO LARGE", i),
        y => println!("{} {}", i, y),
    });
}

Referências

links externos