Domanda

Quindi ho una funzione che assomiglia a questa:

float function(){
    float x = SomeValue;
    return x / SomeOtherValue;
}

Ad un certo punto, questa funzione va in overflow e restituisce un valore negativo molto elevato.Per provare a rintracciare esattamente dove stava accadendo, ho aggiunto un'istruzione cout in modo che la funzione assomigliasse a questa:

float function(){
    float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

e ha funzionato!Naturalmente ho risolto del tutto il problema utilizzando un doppio.Ma sono curioso di sapere perché la funzione ha funzionato correttamente quando l'ho considerata.È tipico o potrebbe esserci un bug da qualche altra parte che mi sfugge?

(Se può esserti d'aiuto, il valore memorizzato nel float è solo un valore intero e non particolarmente grande.L'ho semplicemente messo in un float per evitare il casting.)

È stato utile?

Soluzione

Benvenuti nel meraviglioso mondo della virgola mobile.La risposta che otterrai dipenderà probabilmente dal modello in virgola mobile con cui hai compilato il codice.

Ciò accade a causa della differenza tra le specifiche IEEE e l'hardware su cui è in esecuzione il codice.Probabilmente la tua CPU ha registri a virgola mobile a 80 bit che vengono utilizzati per contenere il valore float a 32 bit.Ciò significa che c'è molta più precisione mentre il valore rimane in un registro rispetto a quando viene forzato in un indirizzo di memoria (noto anche come "homing" del registro).

Quando hai passato il valore a cout, il compilatore ha dovuto scrivere il punto mobile in memoria, e questo si traduce in una perdita di precisione e in casi di overflow WRT con comportamenti interessanti.

Consulta la documentazione MSDN su VC++ interruttori in virgola mobile.Potresti provare a compilare con /fp:strict e vedere cosa succede.

Altri suggerimenti

La stampa di un valore su cout non dovrebbe modificare in alcun modo il valore del parametro.

Tuttavia, ho visto un comportamento simile, l'aggiunta di istruzioni di debug provoca una modifica nel valore.In quei casi, e probabilmente anche questo, la mia ipotesi era che le istruzioni aggiuntive causassero un comportamento diverso dell'ottimizzatore del compilatore, quindi genera codice diverso per la tua funzione.

L'aggiunta dell'istruzione cout significa che il valore di x viene utilizzato direttamente.Senza di essa l'ottimizzatore potrebbe rimuovere la variabile, cambiando così l'ordine del calcolo e quindi cambiando la risposta.

Per inciso, è sempre una buona idea dichiarare variabili immutabili utilizzando const:

float function(){
    const float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

Tra le altre cose questo ti impedirà di passare involontariamente le tue variabili a funzioni che potrebbero modificarle tramite non-const Riferimenti.

cout provoca un riferimento alla variabile, che spesso costringe il compilatore a forzarne il versamento nello stack.

Poiché si tratta di un float, è probabile che il suo valore venga troncato dalla rappresentazione double o long double che avrebbe normalmente.

Chiamare qualsiasi funzione (non in linea) che accetta un puntatore o un riferimento a x dovrebbe finire per causare lo stesso comportamento, ma se il compilatore in seguito diventa più intelligente e impara a in linea, sarai ugualmente fregato :)

Non penso che il cout abbia alcun effetto sulla variabile, il problema dovrebbe essere altrove.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top