2012-03-22 14 views
12

GNU bash, la versione 4.2.24:strano "mezzo per addirittura" arrotondamento in diverse lingue

$> printf "%.0f, %.0f\n" 48.5 49.5 
48, 50 

di Ruby 1.8.7

> printf("%.0f, %.0f\n", 48.5, 49.5) 
48, 50 

Perl 5.12.4

$> perl -e 'printf("%.0f, %.0f\n", 48.5, 49.5)' 
48, 50 

gcc 4.5.3:

> printf("%.0f, %.0f\n", 48.5, 49.5); 
48, 50 

GHC, versione 7.0.4:

> printf "%.0f, %.0f\n" 48.5 49.5 
49, 50 

Wikipedia dice che questo tipo di arrotondamento è chiamato round half to even:

Questa è la modalità predefinita utilizzata in IEEE 754 funzioni di calcolo e gli operatori di arrotondamento .

Perché questo arrotondamento viene utilizzato di default in C, Perl, Ruby e bash, ma non in Haskell?

È una sorta di tradizione o standard? E se è uno standard, perché è usato da quelle lingue e non usato da Haskell? Qual è un punto di arrotondamento a metà persino?

+4

Penso che tu abbia appena risposto alla tua stessa domanda. Fa parte dello standard IEEE 754. –

+0

@Keith Irwin, credo che volesse sapere quale standard. Perché non lo pubblichi come risposta, eventualmente con un link pertinente? – ikegami

+2

Dmitry: la tua domanda menziona specificamente "IEEE 754". Questo è lo standard. – Gabe

risposta

11
GHCi> round 48.5 
48 
GHCi> round 49.5 
50 

L'unica differenza è che non sta usando printfround - presumibilmente perché deve essere in grado di arrotondare a più di interi solo interi. Non penso che IEEE 754 specifichi qualcosa su come implementare le funzioni di formattazione dello stile printf, solo l'arrotondamento, che Haskell fa correttamente.

Probabilmente sarebbe meglio se printf fosse coerente con le implementazioni di round e di altre lingue, ma non penso che sia davvero un grosso problema.

+0

Le funzioni di formattazione in stile printf vengono convertite in un formato decimale in virgola fissa. IEEE 754 consiglia di eseguire conversioni nella modalità di arrotondamento corrente, che è più vicina, anche per impostazione predefinita. Nota che molte lingue/piattaforme continuano a sbagliare a partire dal 2012, usando il più vicino-anche per le conversioni indipendentemente dalla modalità di arrotondamento corrente. –

+5

@PascalCuoq: Grazie per l'informazione! Tuttavia, Haskell semplicemente non può conformarsi a tale raccomandazione, dal momento che 'printf' deve essere una funzione pura. Dovrebbe assumere la modalità di arrotondamento come parametro o operare in un contesto (ad esempio monadico) in cui tale informazione è disponibile. – ehird

+0

Buon punto. Gli standard indipendenti dalla lingua come IEEE 754 lasciano un sacco di ambiguità e possono essere scomodi da soddisfare. Un'altra situazione relativamente simile è la verifica logica Hoare dei programmi a virgola mobile imperativi, in cui si preferisce evitare di pensare alla modalità di arrotondamento come parte aggiuntiva dello stato e dell'argomento del programma a tutte le funzioni in virgola mobile, ma è necessario per gestire i programmi che lo modificano in fase di esecuzione. –

2

Non posso dirlo con certezza, ma questo probabilmente ha a che fare con il fatto che questo tipo di arrotondamento è comunemente usato nelle funzioni contabili, poiché questo è anche noto come arrotondamento del banchiere. Se osservi ulteriormente l'articolo di Wikipedia sull'arrotondamento, noterai anche che questo è l'impostazione predefinita in IEEE 754, quindi probabilmente Haskell non sta seguendo lo standard.

+1

L'articolo Wiki collegato afferma che "L'origine dell'arrotondamento dei banchieri di termine rimane più oscura: se questo metodo di arrotondamento è sempre stato uno standard nel settore bancario, le prove si sono rivelate estremamente difficili da trovare, al contrario, la sezione 2 del Relazione della Commissione L'introduzione dell'euro e l'arrotondamento degli importi in valuta [16] suggerisce che in passato non vi era un approccio standard all'arrotondamento bancario e specifica che gli importi "a metà strada" dovrebbero essere arrotondati __ ". Quindi i banchieri non usano l'arrotondamento del banchiere. –

+0

@ A.H. In realtà, usano ancora l'arrotondamento del banchiere in misura limitata. Posso affermarlo con conoscenza, come lavoravo per un gruppo bancario. –

+0

Ho conoscenza di prima mano dell'arrotondamento utilizzato anche nelle istituzioni finanziarie. Ma non negli Stati Uniti. Ma il pubblico qui è anche internazionale. –

6

"Round to even" è l'impostazione predefinita da utilizzare con IEEE 754. Haskell dovrebbe probabilmente passare a utilizzarlo in printf per motivi di coerenza. La relativa riga di codice è in GHC.Float

f 0 (x:_) = (if x >= b2 then 1 else 0, []) 

Quindi, se qualcuno vuole risolvere il problema, è possibile. Come evidenziato dall'euro, ciò farebbe semplicemente in modo che la funzione roundTo venga utilizzata da printf in modo coerente con round anche se non sono sicuro di quale altro codice questo cambiamento si interromperebbe.

MODIFICA: una versione precedente di questa risposta ha sbagliato la posizione del codice di arrotondamento. L'unica differenza significativa tra le due implementazioni è se sono hardcoded per utilizzare la base 10.

+2

Non penso che sia la linea di codice giusta. 'Text.Printf' funziona con' String', non 'Text'. – ehird

+0

@ehird Text.Printf chiama una funzione di supporto chiamata 'dfmt'' che chiama un altro helper chiamato' dfmt' che chiama 'showFFloat' da Numeric. Quello che fa da lì dipende dall'implementazione, e quando ho risposto a questa domanda pensavo di aver rintracciato il codice GHC nel modulo 'Data.Text', ora ho bisogno di ricontrollare. –

+0

sembra che tu abbia ragione: da GHC 7.4.1 la funzione 'roundTo' chiamata da' formatRealFloat' è inclusa in quel file piuttosto che una chiamata a 'Data.Text.etc'. Fa la stessa cosa, ma è consapevole di base –

Problemi correlati