L'ordine degli argomenti in un'espressione aritmetica è importante per ottenere il risultato più esatto possibile (la velocità non è necessaria)?

4

In realtà, in questa domanda non chiedo di un particolare linguaggio o architettura, tuttavia capisco che potrebbero esserci alcune differenze.

In fisica / ingegneria di solito è meglio gestire numeri più grandi di quelli più piccoli, a causa della migliore precisione assoluta. Per esempio quando ho bisogno di calcolare l'area di un cerchio, avendo il suo diametro, userei l'equazione S = d * d / 4 * pi piuttosto che S = pi * (d / 2) * (d / 2) (in entrambi i casi calcolando da sinistra a destra).

Come appare nei linguaggi di programmazione?

È importante fornire un ordine "migliore" di argomenti? Ci sono dei compilatori che possono ottimizzare il calcolo per questo?

Queste costruzioni hanno un senso:

// finding a result of a*b/c
if (abs(c)<1){
    result = a / c * b;
} else {
    result = a * b / c;
}

(nell'esempio si dovrebbero testare anche i valori di a e b ma assumiamo che siano numeri grandi)?

So che usando numeri troppo grandi sto rischiando un overflow. So che c'è una differenza tra i numeri interi (che sono migliori in addizione / sottrazione) e float (che sono migliori in moltiplicazione / divisione).

C'è anche un problema con la divisione intera, per esempio in Pascal c'è un comune operatore di moltiplicazione * e se entrambi i numeri sono Integer , il risultato è anche Integer , se uno di questi è Real ( equivalente a float ), anche il risultato è Real . Per la divisione ci sono due operatori: / che risulta sempre con Real numero e div che prende solo Integer s e il risultato è Integer . Quindi in questa lingua sarebbe meglio calcolare prima le moltiplicazioni e poi le divisioni perché le divisioni Integer potrebbero portare a perdere la parte frazionaria, ed è meglio perderla più tardi rispetto a prima.

Ma per float numeri, che sono memorizzati con mantissa e esponente l'ordine di moltiplicazioni / divisioni sembra non essere necessario.

Quello che voglio ottenere è il risultato più preciso possibile (la velocità non è necessaria)

    
posta Voitcus 18.09.2015 - 09:45
fonte

3 risposte

5

Ci sono due casi da considerare: moltiplicazione (compresa la divisione) e aggiunta (compresa la sottrazione). Poiché i numeri in virgola mobile sono memorizzati in forma esponenziale (cioè come m * 2 ^ e), queste operazioni vengono eseguite sulla mantissa (m) e sull'esponente (e) come valori separati, non sui numeri interi interessati.

La moltiplicazione (fondamentalmente) implica moltiplicare le mantidi (che sono sempre tra 1 e 2) e aggiungere gli esponenti (che sono numeri interi). Ne consegue che, a meno che l'aggiunta di interi esponenti trabocchi, la magnitudine assoluta dei numeri non fa differenza per la precisione del risultato.

Per aggiunta, tuttavia, le cose sono diverse. Per aggiungere numeri in virgola mobile, una delle mantisse viene spostata di un numero appropriato di bit per rendere uguali gli esponenti, e quindi vengono aggiunte le mantissae. Questa operazione di cambio perde precisione proporzionalmente alla differenza di esponenti. Pertanto, l'aggiunta è più precisa quando gli operandi sono più vicini di grandezza. In pratica, ciò significa che se si aggiungono molti numeri in virgola mobile che possono variare in modo disordinato in ampiezza, è meglio iniziare con il più piccolo (il più vicino allo zero) e avanzare per aggiungere la grandezza maggiore. Numeri alla fine. Se non si conoscono le grandezze relative in anticipo, inserirle in una matrice e ordinare la matrice per la grandezza prima di sommarla. Se lo fai, usa una variabile accumulatore e aggiungi prima i numeri più piccoli.

    
risposta data 18.09.2015 - 10:47
fonte
0

In physics / engineering it is usually better to handle greater numbers than smaller ones, because of better absolute accuracy.

Non penso che questo sia vero affatto. C'è davvero un punto in cui si aggiunge un numero piccolo a un numero grande. Ma per quanto riguarda la divisione della moltiplicazione c'è il rischio di overflow quando si moltiplicano i numeri che sono entrambi maggiori di 1, quindi per esempio

99999999999999999999999 / 9999999999999999999x999999999999999999999999999

è migliore di

99999999999999999999999x99999999999999999999999999999 / 999999999999999999999 perché il successivo può (in alcune macchine) provocare un overflow.

D'altra parte se dividi più volte un'espressione di un numero elevato puoi ottenere un underflow. Quindi, se hai una buona idea dell'ordine di grandezza del numero in questione, è una buona idea interlacciare moltiplicazioni e divisioni per mantenere i risultati intermedi entro l'intervallo di numeri che il computer può rappresentare.

Nel calcolo della tua area S = pi * (d / 2) * (d / 2) è peggio perché c'è un'altra operazione di S = d * d / 4 * pi.

    
risposta data 18.09.2015 - 10:35
fonte
0

In effetti non ho molta conoscenza o idea se usare numeri grandi sia meglio o meno. Ma posso condividere due punti che conosco ...

Il primo è Priorità operatore , che probabilmente conosci. Alcuni operatori hanno priorità più alta di altri (come * verrà eseguito prima di + in 2 * 3 + 1 a meno che non si usi la parentesi).

Per risultati esatti ; ci sono anche due punti. La prima è che la conversione da float a int (o inversa) è specifica per il linguaggio di programmazione e lingue diverse possono agire diversamente. Anche le diverse versioni della stessa lingua possono agire in modo diverso.

Il secondo punto nei risultati esatti è il float type , perché è noto che Floating Point Math potrebbe sembrare rotto , perché i computer utilizzati per calcolare utilizzando binario (base 2) in modo che il numero è rappresentato come la potenza di due. Non è facile rappresentare 0.2 con la potenza di 2 e ciò che ottieni è 0.001100110011001... o simile. Usando la moltiplicazione o la divisione molte volte su valori in virgola mobile, questa differenza diventa sempre più grande. di David Goldberg che cosa ogni scienziato informatico dovrebbe sapere sull'aritmetica virgola mobile ha ottime informazioni su questo argomento.

Python ha Decimale che può calcolare e memorizzare il valore esatto di un numero decimale rappresentato. La maggior parte dei linguaggi di programmazione ha tipi di dati simili come quello.

    
risposta data 18.09.2015 - 10:19
fonte