Tutte le lingue complete sono intercambiabili


26

Nota, mentre so programmare, sono abbastanza principiante alla teoria CS.

Secondo questa risposta

La completezza di Turing è un concetto astratto di calcolabilità. Se una lingua è Turing completa, allora è in grado di fare qualsiasi calcolo che può fare qualsiasi altra lingua completa di Turing.

E qualsiasi programma scritto in qualsiasi linguaggio completo di Turing può essere riscritto in un altro .

Ok. Questo ha senso. Posso tradurre (compilare) C in Assembly (e lo faccio tutti i giorni!), E posso tradurre Assembly in C (Puoi scrivere una macchina virtuale in C). E lo stesso vale per qualsiasi altra lingua: è possibile compilare qualsiasi lingua in Assembly e quindi eseguirla in una macchina virtuale scritta in un'altra lingua.

Ma un programma scritto in una lingua completa di Turing può essere riscritto in un'altra?

Cosa succede se il mio assembly ha un codice operativo LIGHTBUTTON? Non riesco fisicamente a emulare quella lingua su un sistema (lingua) senza una lampadina.

Ok. Quindi dirai che dal momento che abbiamo a che fare con la teoria dei computer , non stiamo discutendo le limitazioni dei dispositivi fisici.

Ma che dire di un dispositivo che non ha moltiplicazione? divisione? Per quanto ne so (anche se questa è più una domanda per math.SE), non si può emulare la moltiplicazione (e sicuramente non la divisione) con addizione e sottrazione [1].

In che modo un "linguaggio completo turing" (che può aggiungere, sottrarre e saltare) emulerebbe un'altra lingua che può aggiungere, sottrarre, moltiplicare e saltare?

MODIFICARE

[1]. Su numeri reali arbitrari.


33
I numeri reali appartengono al regno del calcolo Hyper-Turing. Una macchina di Turing non può gestire numeri reali, ergo, sono irrilevanti per la completezza di Turing.
Jörg W Mittag,

3
Correlati: un set di istruzioni in linguaggio assembly con una sola istruzione è ancora abbastanza potente per costruire un computer universale: en.wikipedia.org/wiki/One_instruction_set_computer . Ad esempio, "Sottrai e ramifica se inferiore o uguale a zero" con operandi di memoria. Sarà lento rispetto a un moderno x86, ma il rapporto prestazioni è limitato per qualsiasi programma.
Peter Cordes,

1
Nessuna macchina fisica (attualmente esistente) è o può mai essere completa di Turing, perché la completezza di Turing richiede una memoria infinita e l'universo non è infinito. Ne consegue che la risposta affermativa sull'equivalenza di due macchine astratte non aiuta a rispondere alla domanda se due approssimazioni fisiche di tali macchine siano equivalenti.
Ben

2
@PeterCordes: suppongo che quando dici che il rapporto è finito, intendi semplicemente che qualsiasi attività che si completa in un tempo finito su entrambi lo farà in un tempo finito su entrambi - non che per qualsiasi macchina particolare (escluso l'input) ci sarebbe qualsiasi limite finito a quanto alto potrebbe ottenere il rapporto per alcuni input. Penso che si potrebbero costruire macchine complete di Turing per le quali si potrebbero selezionare input che renderebbero il rapporto arbitrariamente alto - forse nemmeno una funzione calcolabile della dimensione dell'input.
supercat

6
Non so da dove venga l'idea che "non si può emulare la moltiplicazione (e sicuramente non la divisione) con addizione e sottrazione". Ci è stato insegnato dalla scuola elementare quando impariamo a moltiplicarci
phuclv il

Risposte:


55

La completezza di Turing dice solo una cosa e una sola cosa: un modello di calcolo è completo di Turing, se qualsiasi calcolo che può essere modellato da una Macchina di Turing può anche essere modellato da quel modello.

Quindi, quali sono i calcoli che una macchina di Turing può modellare? Bene, prima di tutto, Alan Turing e tutti i suoi colleghi erano sempre e solo interessati alle funzioni sui numeri naturali. Quindi, la Turing Machine (e il calcolo λ, il calcolo del combinatore SK, le funzioni ricorsive μ, ...) parlano solo della calcolabilità delle funzioni sui numeri naturali. Se non stai parlando di una funzione su numeri naturali, allora il concetto di completezza di Turing non ha nemmeno senso, semplicemente non è applicabile.

Si noti, tuttavia, che possiamo codificare molte cose interessanti come numeri naturali. Possiamo codificare stringhe come numeri naturali, possiamo codificare grafici come numeri naturali, possiamo codificare booleani come numeri naturali. Possiamo codificare le macchine di Turing come numeri naturali, il che ci consente di creare macchine di Turing che parlano di macchine di Turing!

E, naturalmente, non tutte le funzioni sui numeri naturali sono calcolabili. Una macchina di Turing può calcolare solo alcune funzioni su numeri naturali, il calcolo λ può calcolare solo alcune funzioni su numeri naturali, il calcolo del combinatore SK può calcolare solo alcune funzioni su numeri naturali, ... Sorprendentemente (o no), si scopre che ogni modello di calcolo (che è effettivamente realizzabile nel nostro universo fisico) può calcolare le stesse funzioni su numeri naturali (almeno per tutti i modelli che abbiamo trovato fino ad ora). [Nota: ovviamente, ci sono modelli di calcolo più deboli , ma non ne abbiamo ancora trovato uno più forte, ad eccezione di alcuni che sono ovviamente incompatibili con il nostro universo fisico, come modelli che utilizzano numeri reali o viaggi nel tempo.]

Questo fatto, che dopo molto tempo alla ricerca di molti modelli diversi, troviamo, ogni volta, che possono calcolare esattamente le stesse funzioni, è la base per la Church-Turing-Thesis, che dice (approssimativamente) che tutti i modelli di calcolo sono ugualmente potenti e tutti catturano la nozione "ideale" di cosa significhi essere "calcolabili". (C'è anche un secondo aspetto più filosofico della CTT, ovvero che un essere umano che segue un algoritmo può anche calcolare esattamente le stesse funzioni che una TM può calcolare e non di più.)

Tuttavia , nulla di tutto ciò dice nulla

  • quanto sono efficienti i vari modelli
  • quanto sono convenienti da usare
  • che cosa altro si può fare oltre a funzioni di calcolo sui numeri naturali

E che è proprio dove le differenze tra i diversi modelli di calcolo (e di linguaggi di programmazione) entrano in gioco.

Come esempio di prestazioni diverse, sia una macchina ad accesso casuale che una macchina di Turing possono copiare un array. Ma una RAM ha bisogno di operazioni per farlo, mentre una TM ha bisogno di operazioni , poiché deve saltare elementi dell'array per copiare ogni elemento e ci sono elementi da copiare.O ( s i z e 2 a r r a y ) s i z e a r r a y s i z e a r r a yO(sizearray)O(sizearray2)sizearraysizearray

A titolo di esempio per convenienza diversa, puoi semplicemente confrontare il codice scritto in un linguaggio di alto livello, il codice scritto in assembly e la descrizione di una TM per risolvere lo stesso problema.

E il tuo interruttore della luce è un esempio del terzo tipo di differenza, cose che alcuni modelli possono fare che non funzionano sui numeri naturali e quindi non hanno nulla a che fare con la completezza di Turing.

Per rispondere a domande specifiche:

Ma un programma scritto in una lingua completa di Turing può essere riscritto in un'altra?

No. Solo se il programma calcola una funzione calcolabile di Turing su numeri naturali. E anche allora, potrebbe essere necessaria una codifica complessa. Ad esempio, λ-calculus non ha nemmeno numeri naturali, devono essere codificati usando le funzioni (perché le funzioni sono l'unica cosa che λ-calculus ha).

Questa codifica di input e output può essere molto complessa, così come l'espressione dell'algoritmo. Quindi, mentre è vero che qualsiasi programma può essere riscritto, il programma riscritto può essere molto più complesso, molto più grande, usare molta più memoria ed essere molto più lento.

Cosa succede se il mio assembly ha un codice operativo LIGHTBUTTON? Non riesco fisicamente a emulare quella lingua su un sistema (lingua) senza una lampadina.

Una lampadina non è una funzione calcolabile di Turing su numeri naturali. In realtà, una lampadina non è né una funzione né un calcolo. L'accensione e lo spegnimento di una lampadina è un effetto collaterale di I / O. Le macchine di Turing non modellano gli effetti collaterali I / O e il completamento di Turing non è rilevante per loro.

Su numeri reali arbitrari.

La completezza di Turing si occupa solo di funzioni calcolabili su numeri naturali, non si occupa di numeri reali.

La completezza di Turing non è semplicemente molto interessante quando si tratta di domande come la tua per due motivi:

  1. Non è un ostacolo molto alto. Tutto ciò che serve è IF, GOTO, WHILE, e una variabile singolo intero (assumendo che la variabile può contenere arbitrariamente grandi numeri interi). Oppure, ricorsione. Un sacco di cose è pieno di Turing. Il gioco di carte Magic: The Gathering è Turing completo. CSS3 è Turing completo. Il sendmailfile di configurazione è Turing completo. La MMU Intel x86 è Turing completa. Le MOVistruzioni Intel x86 sono Turing complete. Le animazioni di PowerPoint sono complete di Turing. Excel (senza script, utilizzando solo le formule) è Turing-complete. Il protocollo di routing BGP è Turing completo. sedè Turing completo. Le mod_rewriteregole di Apache sono Turing complete. Google per " (accidentalmente o sorprendentemente) turing completato"per trovare altri esempi interessanti. Se quasi tutto è Turing completo, essere Turing completo non è più una proprietà interessante.
  2. Non è effettivamente necessario per essere utile. Molte cose utili non sono complete di Turing. CSS prima versione 3 non è Turing-complete (e il fatto che CSS3 è in realtà non è utilizzato da chiunque). SQL prima del 1999 non era completo di Turing, eppure era straordinariamente utile anche allora. Il linguaggio di programmazione C senza librerie aggiuntive non sembra essere completo di Turing . Le lingue tipicamente dipendenti sono, più o meno per definizione, non complete di Turing, tuttavia è possibile scrivere sistemi operativi, server Web e giochi in esse.

Edwin Brady, l'autore di Idris, usa il termine "Tetris-complete" per parlare di alcuni di questi aspetti. Essere completo su Tetris non è rigorosamente definito (a parte l'ovvio "può essere usato per implementare Tetris"), ma comprende cose come essere abbastanza di alto livello ed espressivo da poter scrivere un gioco senza impazzire, potendo interagire con il mondo esterno (input e output), essere in grado di esprimere effetti collaterali, essere in grado di scrivere un loop di eventi, essere in grado di esprimere la programmazione reattiva, asincrona e concorrente, essere in grado di interagire con il sistema operativo, essere in grado interagire con librerie straniere (in altre parole: essere in grado di chiamare ed essere chiamato con il codice C) e così via. Queste sono caratteristiche molto più interessanti di un linguaggio di programmazione generico rispetto alla completezza di Turing.


Potresti trovare interessante la mia risposta alla domanda che hai collegato , che tocca alcuni degli stessi punti anche se risponde a una domanda diversa.


7
Mi piace molto questa risposta, ma penso che valga la pena notare che possiamo rappresentare ogni sorta di cose interessanti con numeri naturali. Ad esempio possiamo rappresentare stringhe con numeri naturali, possiamo rappresentare grafici con numeri naturali, possiamo rappresentare l'intero stato della memoria di un computer con un numero naturale. I numeri reali possono essere codificati come funzioni su numeri naturali e (molte) funzioni su numeri naturali possono essere codificati da numeri naturali. Quindi limitare le funzioni da numeri naturali a numeri naturali non è una grande limitazione, a meno che non sia buio e si desideri che il computer accenda la luce.
Theodore Norvell,

3
Bella risposta, ma questo: "essere completo di Turing smette di essere una proprietà interessante" è semplicemente sbagliato. Se qualcosa è Turing completo, allora il suo problema di arresto è Turing completo mediante riduzione calcolabile al problema di arresto per le macchine Turing. Ad esempio, il gioco di carte Magic: The Gathering è Turing completo. Ciò significa che le sue regole sono indecidibili , cioè nel caso generale è impossibile dedurre calcolabilmente quale sarà il seguente stato di gioco, che è una proprietà molto interessante. Più seriamente, usiamo la completezza e le riduzioni di Turing per dimostrare problemi indecidibili.
quicksort

Turing e i suoi colleghi erano interessati alle funzioni sui numeri naturali, ma le macchine di Turing in realtà non gestiscono i numeri, si occupano di stringhe di simboli. Ovviamente puoi interpretare banalmente tratti finiti di simboli in un alfabeto finito noto come numeri naturali, ma le TM non fanno direttamente cose "numerose" con il loro input, ma semplicemente manipolano le "cifre". In realtà ha bisogno di un po 'di logica per passare dalle descrizioni standard delle TM alle "funzioni su numeri naturali"; quando si lavora con TM si codificano numeri naturali come stringhe, non stringhe come numeri.
Ben

Questa è ovviamente un'ottima risposta, ma temo che vada oltre la comprensione di OP. OP è già confuso sull'implementazione della moltiplicazione su (sottoinsiemi finiti di) numeri reali. Detto questo, la tua risposta sembra implicare che i linguaggi di programmazione completi di Turing non sono, in effetti, scambiabili ai fini del puro calcolo, quando in realtà lo sono (perché tutto ciò che fanno le moderne CPU - non solo alcune cose - può essere codificato come naturale numeri).
Konrad Rudolph,

9
@TheodoreNorvell In tema di codifica di numeri reali con numeri naturali. In effetti, quasi tutti i numeri reali non possono essere codificati da numeri naturali. L'insieme di numeri reali che possono essere codificati da numeri naturali, in virtù della loro codifica da numeri naturali, è al massimo numerabile infinito. E poiché è solo infinitamente numerabile, l'insieme ha misura zero. È un po 'disonesto dire che possiamo rappresentare numeri reali in generale con numeri naturali poiché possiamo rappresentarne solo una frazione infinitesimale, o per essere più precisi: 0%.
Shufflepants

9

Ovviamente puoi implementare la moltiplicazione con addizione e sottrazione:

/* Assume b is positive for simplicity */
int multiply(int a, int b) {
  int res = 0;
  while (b > 0) { res += a; b -= 1; }
  return res;
}

Il fatto che probabilmente non lo faresti non lo rende meno possibile.

La divisione non è quasi più difficile:

/* Assume a and b are positive for simplicity */
int divide(int a, int b) {
  int res = 0;
  while (a >= b) { res += 1; a -= b; }
  return res;
}

E come pensi che la moltiplicazione e la divisione siano effettivamente eseguite dai circuiti della CPU? Suggerimento: non è un'enorme tabella di ricerca. È più efficiente di quanto sopra, poiché viene utilizzato anche lo spostamento dei bit, ma è fondamentalmente implementato in termini di addizione e sottrazione.


4
@touring: funziona benissimo in virgola mobile. Per prima cosa normalizzi le mantisse in modo che il numeratore abbia 0 binari finali. Quindi fai la divisione intera. Finalmente correggi l'esponente: differenza degli esponenti originali più la correzione dalla normalizzazione. 2precision
rici,

7
@touring: sai, l'aritmetica in virgola mobile era disponibile prima che esistessero coprocessori in virgola mobile.
rici,

6

Nessuna macchina fisica (attualmente esistente) è o può mai essere completa di Turing, poiché la completezza di Turing richiede una memoria infinita e l'universo non è infinito.

Ne consegue che la risposta affermativa sull'equivalenza di due macchine astratte non aiuta a rispondere alla domanda se due approssimazioni fisiche di tali macchine siano equivalenti.

Pertanto, l'equivalenza di Turing dei modelli astratti di (ad esempio) due lingue non significa che ciascuno possa calcolare in pratica tutto ciò che l'altro può calcolare. Uno può imbattersi in limiti fisici prima dell'altro.


Ma la domanda posta sulle lingue. Menziona macchine particolari, ma solo perché non si rende conto che praticamente nessuna macchina reale opera su numeri reali.
Shufflepants,

3

È possibile implementare la moltiplicazione e la divisione rispettivamente come addizione e sottrazione ripetute, osservando che e .nm=n+n(m1)m/n=1+(mn)/n

È un dato di fatto, le operazioni "aggiungi 1", "sottrai 1" e "salta condizionale se un registro specificato è zero" sono sufficienti per rendere Turing un modello computazionale (vedi la macchina a 2 contatori come riferimento per un modello computazionale completo di Turing molto minimale).

È anche possibile implementarli in modo da preservare la complessità computazionale. Prima di tutto, osserva che la moltiplicazione per è "libera" ( ). Usando la moltiplicazione per , il loop e la sottrazione possiamo facilmente implementare l'algoritmo euclideo per la divisione per due. Con la moltiplicazione e la divisione per due, possiamo implementare l'algoritmo russo per la moltiplicazione, osservando che e . Con la moltiplicazione arbitraria, possiamo finalmente implementare l'algoritmo euclideo completo per la divisione.22n=n+n2m×2n=2m×nm×(2n+1)=m+2m×n


3

tl; dr - Le macchine di Turing sono solo una descrizione logica di base per il funzionamento di un sistema logico generale. Possono fare la maggior parte delle cose che possiamo descrivere, incluso chiamare codici operativi specializzati e costruire operazioni matematiche.


Cosa succede se il mio assembly ha un codice operativo LIGHTBUTTON? Non riesco fisicamente a emulare quella lingua su un sistema (lingua) senza una lampadina.

In un modello Turing, i simboli come un LIGHTBUTTONcodice operativo sono solo stringhe in qualsiasi alfabeto utilizzato dal computer Turing.

Quindi, la macchina di Turing sarebbe responsabile della produzione della stringa "LIGHTBUTTON", o di un valore intero che corrisponde a quel codice operativo; se un'entità esterna agisca o meno su di essa non è affare del computer Turing.

I programmi C hanno la stessa limitazione. Ciò significa che un programma C può chiamare solo il codice LIGHTBUTTONoperativo, anche se la CPU esegue effettivamente un'operazione associata a quel codice operativo dipende dalla CPU.


Ma che dire di un dispositivo che non ha moltiplicazione? divisione? Per quanto ne so (anche se questa è più una domanda per math.SE), non si può emulare la moltiplicazione (e sicuramente non la divisione) con addizione e sottrazione [su numeri reali arbitrari].

Sì, una macchina di Turing potrebbe fare quelle cose, anche su numeri reali, nella misura in cui qualsiasi logica descrivibile dall'uomo potrebbe farlo. La macchina Turing potrebbe essere semplice come un'automazione cellulare Rule 110 .

Il trucco è costruire un sistema logico da qualunque fisica abbia la macchina naturalmente. Ad esempio, le CPU tradizionali possono fare moltiplicazioni e divisioni perché hanno unità logiche aritmetiche (ALU) . Ma gli ALU non sono magici; sono solo semplici porte logiche . E quelle porte logiche sono costituite da transistor . E quei transistor sono fatti di sabbia drogata .

Quindi, per ottenere un dispositivo completo di Turing per fare matematica, devi solo programmarlo in quel modo.

In effetti, puoi fare un vero calcolo sulle macchine di Turing! Per dimostrarlo, ecco WolframAlpha calcolando . Voglio dire, certo, le macchine di Turing non possono espandersi all'infinito in tempi limitati, ma va bene; nessuno si espande all'infinito , compresi gli esseri umani. Ma se accreditiamo agli umani di fare matematica con numeri reali, ad esempio , allora dobbiamo dare credito alle macchine di Turing per lo stesso.ππ=0π π - π = 0ππππ=0


3

Ma un programma scritto in una lingua completa di Turing può essere riscritto in un'altra?

Se l'ingresso al programma è una sequenza di bit arbitrariamente lunga e anche l'uscita è una sequenza di bit arbitrariamente lunga, allora SÌ. Supponendo che tu abbia il tempo e l'energia per riscriverlo e che non ti interessi alle prestazioni e che hai memoria fisica sufficiente per entrambe le implementazioni.

Le considerazioni pratiche che significano che due lingue complete di Turing non sono intercambiabili includono:

  • supportano diversi tipi di input e output (es. accesso al database SQL)

  • hanno diverse librerie di tipi di dati (ad es. supporto per stringhe Unicode)

  • forniscono paradigmi di programmazione diversi ottimizzati per compiti diversi (ad es. oggetti, thread, coroutine, funzioni di prima classe)

  • forniscono diverse librerie di funzioni (ad es. analisi XML e serializzazione)


1

No. La completezza di Turing non ha nulla a che fare con i programmi , riguarda funzioni matematiche (o algoritmi ). Qualsiasi algoritmo - qualsiasi calcolo - puoi fare in C, puoi farlo in qualsiasi altro linguaggio completo di Turing (questo dovrebbe essere ovvio). Ma la completezza di Turing in realtà non dice che puoi fare l'I / O - affatto. Non parla affatto dell'hardware. Solo i calcoli.

È possibile estendere un linguaggio completo di Turing con qualsiasi operazione hardware desiderata (tecnicamente, ecco come fputce fgetcfunziona in C). Se prendi due lingue complete di Turing e le estendi con operazioni identiche specifiche dell'hardware, rimangono intercambiabili. Quindi il tuo linguaggio assembly con LIGHTBULBoperazione è più potente di Turing-complete; potresti dire che è finito TuringLIGHTBULB . Per rendere qualsiasi altra lingua identica ad essa, deve anche essere completata da Turing LIGHTBULB; il modo più semplice per farlo è quello di aggiungere una LIGHTBULBprimitiva / istruzione / funzione / ecc.

Questo è il motivo per cui le implementazioni in C generalmente supportano l'assemblatore in linea o documentano un modo per chiamare funzioni scritte in assemblatore e perché le implementazioni di altre lingue generalmente forniscono un modo per chiamare funzioni scritte in C.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.