Esiste un linguaggio di programmazione in cui 1/6 si comporta come 1.0 / 6.0?


11

Mentre stavo programmando in C ++ qualche giorno fa, ho fatto questo errore (che ho la storia di farlo!). In una parte del mio codice, avevo 1/6 e mi aspettavo che fosse 0.16666666666 che non è il caso. Come tutti sapete, il risultato è 0 - C, C ++, Java, Python, si comportano tutti allo stesso modo.

Lo pubblico sulla mia pagina Facebook e ora si discute se esiste un linguaggio di programmazione in cui 1/6si comporta come 1.0/6.0.


5
Haskell. 1/6 = 0.16666666666666666
t123

PowerShell genera 0.166666666666667, il che mi ha sorpreso poiché 1 è un numero intero. Scommetto che ci sono altri linguaggi .NET che generano il valore che ti aspettavi.
JohnL

In teoria ce ne sono un numero illimitato. Eccone un altro: Rebol , così come derivati ​​come Orca, Red e così via. >> 1 / 6->== 0.166666666666667
Izkata,

Lua fa questo. Ha solo un singolo tipo Numero , che di solito è lo stesso del doppio di C.
Machado,

In Clojure 1/6è in realtà 1/6 (tipo frazionario) che, costretto a Double, è 1.66666 ...
kaoD

Risposte:


17

Tutti hanno dimenticato Pascal?

1/6rendimenti 0.1666666...(a qualunque precisione sia supportata).

1 div 6 i rendimenti 0

È discutibile se la regola C sia un errore. Quasi tutti gli operatori aritmetici di C, in cui gli operandi sono dello stesso tipo, producono un risultato dello stesso tipo. C'è qualcosa da dire per coerenza.

Inoltre, poiché C è principalmente indirizzato al codice a livello di sistema, la maggior parte dei programmi C non utilizza affatto il virgola mobile. Una volta, l'aggiunta accidentale di codice in virgola mobile a un programma che altrimenti non ne aveva bisogno potrebbe essere un problema serio. Questo è probabilmente ancora il caso, per i piccoli sistemi embedded - che, ancora una volta, sono un obiettivo importante per C.

Nella maggior parte dei programmi C, troncare la divisione intera è probabilmente proprio quello che vuoi comunque.

Se ha 1 / 6prodotto un risultato in virgola mobile in C, quindi:

  • Sarebbe un'incoerenza nella lingua.
  • Lo standard dovrebbe fare una scelta arbitraria di quale tipo a virgola mobile utilizzare per il risultato ( doublepuò sembrare la scelta naturale, ma potresti preferire la precisione extra di long double)
  • La lingua dovrebbe comunque avere un'operazione per la divisione di numeri interi; eseguire l'aggiunta in virgola mobile e quindi troncare non sarebbe probabilmente abbastanza buono.

C avrebbe potuto fornire operatori separati per i due tipi di divisione, ma si applicherebbe comunque il secondo punto precedente: quale dei tre tipi in virgola mobile sarebbe usato per il risultato? E dal momento che è abbastanza facile ottenere una divisione in virgola mobile se ne hai bisogno (usa una costante in virgola mobile per uno o entrambi gli operandi o esegui il cast di uno o entrambi gli operandi in un tipo in virgola mobile), a quanto pare non lo era considerato importante.

Nella versione del manuale C del 1974 (4 anni prima della pubblicazione della prima edizione di K&R), Ritchie non menziona nemmeno la possibile confusione:

Il binario / operatore indica la divisione. Si applicano le stesse considerazioni sul tipo della moltiplicazione

che dice che se entrambi gli operandi sono di tipo into char, il risultato è di tipo int.

Sì, è fonte di confusione per alcuni programmatori C, in particolare i principianti, ma C non è noto per essere molto adatto ai principianti.


5
Pascal. Ottenere dettagli prima che C li avesse sbagliati. ™
Mason Wheeler,

E poi Algol è stato un miglioramento rispetto ai suoi successori (nel numero di cui sono in piedi sia C che Pascal).
Approgrammatore

Pascal - ottenere i dettagli giusti (dare o prendere un fattore 10)
Martin Beckett

1
Inizialmente ho scritto 1.666666..., il che è chiaramente sbagliato. La mia scusa zoppa è che il programma di test Pascal che ho scritto stampato1.6666666666666667E-0001
Keith Thompson il

16

In realtà questo comportamento è stato modificato in Python 3 e ora si comporta come previsto ( //ora viene utilizzato per la divisione di numeri interi).


Grazie. Hai in mente altri linguaggi di programmazione? Famiglia di base forse?
Pouya,

1
@Pouya: questo comportamento è standard per la famiglia Pascal. /produce sempre un valore in virgola mobile e un operatore separato ( div) viene utilizzato per la divisione di numeri interi.
Mason Wheeler

13

Di lingue importanti, JavaScript. 1.0 / 6.0 = 1/6 = 0.16666666666666666.

Non lo vedo sorprendente. Come regola generale, se una lingua distingue tra numeri interi e tipi in virgola mobile, la divisione di due numeri interi produrrà un numero intero troncato anziché float. In caso contrario, molto probabilmente per impostazione predefinita saranno operazioni in virgola mobile. Questo dovrebbe essere il comportamento previsto da parte del programmatore.

Tieni presente che ci sono altre cose che potrebbero anche essere in gioco qui, come il già citato operatore di divisione di numeri interi separati o il cast di tipi impliciti.


6
Questa non è "una regola empirica". È una regola di C e una manciata di lingue che ha copiato ciecamente gli errori di C.
Mason Wheeler,

4
@MasonWheeler: FORTRAN ha "copiato ciecamente l'errore di C"? Personalmente credo che linguaggi ben progettati dovrebbero usare operatori separati per la divisione troncata rispetto alla divisione approssimativa delle quantità intere (e anche, tra l'altro, per valore e uguaglianza referenziale), ma la decisione di progettazione ai tempi di FORTRAN era probabilmente ragionevole. Ciò non significa che ogni lingua dovrebbe fare le cose come FORTRAN negli anni '50.
supercat

3
Le lingue di livello inferiore devono fare queste distinzioni. Le lingue di livello superiore / dinamico spesso vanno meglio senza di esse. È un compromesso di progettazione. Apprezzo solo avere un grande costruttore / tipo di stupido numero in JS, ma immagino che mi sentirebbe carente JS quando provo a scrivere un motore 3D ad alte prestazioni senza un controllo del tipo più rigoroso. JS potrebbe avere un'utilità sovrapposta con altre lingue, ma non credo che nessuno lo considererà mai un goto per scrivere roba di tipo più vicino al cromo ad alte prestazioni.
Erik Reppen,

2
La matematica al di fuori della programmazione considera le regole per la divisione solo per numeri interi.
Erik Reppen,

5
@MasonWheeler: la programmazione non è pura matematica. Matematicamente, 1/6 è un numero razionale e non può essere rappresentato esattamente da un numero binario in virgola mobile. L'unica rappresentazione precisa è come un rapporto con un denominatore sei volte il numeratore.
Kevin Cline,

7

Esistono molte lingue in cui i ((1/6)*6)risultati sono 1, non in 0. Ad esempio, PL / SQL, molti dialetti BASIC, Lua.

Per inciso, in tutti quei linguaggi 1/6 risulta in .166666667, o 0.166666666666666 o qualcosa di simile. Ho scelto la variante ((1/6) * 6) == 1 per eliminare quelle piccole differenze.


7
Non è questa la domanda.
Roc Martí,

20
Per inciso, in tutti quei linguaggi 1/6 risulta in .166666667, o 0.166666666666666 o qualcosa di simile. Ho scelto la ((1/6)*6)==1variante per sbarazzarmi di quelle piccole differenze, ma sembra che abbia sopravvalutato le abilità matematiche di alcune persone.
user281377

1
@ RocMartí sì, è davvero ...
MattDavey

1
Sarei sorpreso di vedere (1.0 / 6.0) * 6 esattamente uguale a 1! L'arrotondamento del risultato di (1.0 / 6.0) comporterà una piccola differenza. (Anche se ci saranno alcune lingue per impostazione predefinita alla precisione infinita)
Sjoerd

1
@Sjoerd: In realtà non è troppo sorprendente che sia esatto. Considerare in decimale lo scenario di 1/11 * 11 con tutti i valori precisi a cinque cifre significative. Il valore di 1/11 è 9.0909 * 10 ^ -2. Moltiplicare per 11 e si otterrebbe 99.9999 * 10 / -2 prima dell'arrotondamento. Arrotonda a cinque cifre significative e il risultato sarà 1,0000 * 10 ^ 0. Nota che la chiave è che la mantissa di 1/6 è "... 0101010101 ...". Se l'ultimo bit di una rappresentazione è un "1", moltiplicandolo per sei e arrotondando si otterrà 1. Se l'ultimo bit fosse zero, non lo sarebbe.
supercat

3

Haskell considera 1/6 e 1.0 / 6.0 identici allo 0,16666666666666666. Rende anche 1 / 6.0 e 1.0 / 6 come lo stesso valore.

Ciò è dovuto al fatto che i tipi numerici di base in Haskell non sono abbastanza gli stessi di altre lingue. La vera divisione dei numeri interi è in qualche modo ... complicata.


2

Sì, Perl lo fa. Il one-liner

perl -e '$x=1/6;print "$x\n";'

provoca l'output di:

0.166666666666667

Credo che PHP funzioni allo stesso modo.

Modificato per aggiungere: credo anche che una condizione necessaria (ma non sufficiente) 1/6 == 1.0/6.0per la lingua in questione sia tipizzata debolmente.


Perché diavolo sarebbe necessaria una digitazione debole (qualunque cosa si supponga significhi)? Basta definire / per (anche) significare divisione float nel caso in cui entrambi gli argomenti siano numeri interi.

1
@delnan - en.wikipedia.org/wiki/Weak_typing Suppongo che potrebbe essere possibile avere un linguaggio fortemente tipizzato in cui /viene automaticamente sovraccaricato a seconda dei tipi di argomenti, ma sembra una violazione del Principio del minimo stupore per io ...

2
La digitazione debole / forte è mal definita (come implica anche wiki), si prega di evitarlo ed essere specifici. Presumo che la tua definizione vieti la conversione implicita, ma non il polimorfismo ad hoc? Se è così, considera Haskell, che non ha conversioni implicite ma abbastanza ben eseguito (come in, funziona il 99% delle volte e può essere compreso dai mortali) polimorfismo numerico. E perché sarebbe sorprendente? Sarebbe molto più sorprendente (per non dire fastidioso) se dovessi aggiungere un numero di punti a ogni singola istanza di qualsiasi operatore, a seconda dell'esatta precisione che desidero.

2
@JackManey Penso che per la maggior parte dei nuovi arrivati ​​sia molto più sorprendente che 1/2 dovrebbe essere uguale a 0 di quanto lo sia se la divisione di due numeri interi si traduce in un doppio. Dopo che tutti gli interi non sono chiusi sotto divisione in matematica. Inoltre, come sottolinea Delnan, Haskell è un esempio di un linguaggio fortemente tipizzato in cui / su due numeri interi, non produce un numero intero. E Python 3 è un altro.
sepp2k,

1
Il linguaggio Haxe è fortemente tipizzato (sebbene inferito), eppure non ha divisione intera, ma solo float. Quindi eccoti.
K.Steff,

2

In Squeak Smalltalk /sugli interi crea oggetti Fraction. Quindi, sebbene ciò non coincida con la divisione float, (1/6)*6restituisce comunque 1.


In tutti i derivati ​​Smalltalk-80 (cioè quasi tutti i Smalltalk). L'ambra è una delle eccezioni contemporanee (che è comprensibile, essendo compilata in JavaScript).
citato il

2

Sì, ho appena controllato la mia TI-99 / 4A costruita in TI BASIC . Poiché tratta tutte le espressioni numeriche come virgola mobile, anche l'operazione di divisione è virgola mobile.

 TI BASIC READY
>PRINT 1/6
  .1666666667

>


2

MATLAB. I letterali numerici sono i doppi per impostazione predefinita.

>> 1/6
ans =
    0.1667

2

Clojure usa le frazioni di default. Non è lo stesso di 1.0 / 6.0, ma puoi convertirlo con floato doublequando ti serve.

user=> (/ 1 6)
1/6
user=> (* (/ 1 6) 2)
1/3
user=> (pos? (/ 1 6)) ; Is 1/6 > 0?
true
user=> (float (/ 1 6))
0.16666667

1

Sorprendentemente, sembra funzionare correttamente in Windows PowerShell (versione 3) .

PS C:\> 1.0 / 6.0
0.166666666666667

PS C:\> 1/6
0.166666666666667

Sembra funzionare anche in Python 3 come menzionato sepp2k. Le altre due lingue che ho prontamente disponibile su REPL, Scala e Ruby, entrambe fanno divisione intera e danno 0.


0

Il linguaggio Rexx produce sempre una risposta aritmeticamente corretta. Ad esempio: 5/2 = 2.5. Rexx è un linguaggio eccezionale che non è stato abbastanza utilizzato. In teoria, quando un compilatore non è in grado di determinare cosa vuoi, è meglio fare la matematica corretta, tuttavia, questo potrebbe non essere efficiente. Rexx fornisce anche l'operatore //.

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.