2016-01-19 6 views
6

Sto scrivendo un programma in cui ci sono alcune operazioni eseguite su un numero in virgola mobile. Dopo aver eseguito il debug del programma, sono venuto a sapere che per un caso di test specifico, il valore di variable equals -2.38418579e-07. Ora ho la precisione cout impostata su 2 cifre dopo i decimali. Così, quando lo stampo, lo stampa come -0,00.Come sbarazzarsi di -0 in C++

Tuttavia, vorrei che l'uscita fosse 0.00 anziché -0.00. Ho provato varie condizioni if sul valore della variabile. Tuttavia, non aiutano. Qualcuno può suggerire come sbarazzarsi di -0.00 in C++

+0

'std :: signbit' dovrebbe aiutare. – Florian

+3

Perché non basta intorno ad esso? –

+5

Per quanto riguarda il controllo dell'output: 'if (output ==" -0.00 ") output =" 0.00 ";' (supponendo che l'output sia uno std :: string) –

risposta

3

In primo luogo, è necessario definire un numero di tolleranza come soglia, in cui il valore assoluto di qualsiasi numero in virgola mobile inferiore a questa soglia sarebbe considerato pari a zero. Per esempio si potrebbe definire questa soglia come:

#define zero 1e-6 

allora si potrebbe utilizzare le seguenti costruire di "filtrare" i tuoi numeri in virgola mobile:

template<typename T> 
std::enable_if_t<std::is_floating_point<T>::value, T> sanitize(T &&num) { 
    return std::abs(num) < zero? T{} : num;  
} 

Live Demo

Si noti che io uso SFINAE in ordinare la funzione sanitize per accettare come input solo numeri in virgola mobile.

+3

Perché il && ref? –

0

vorrei l'uscita per essere 0.00 invece di -0,00

mi piacciono le altre risposte migliori. Ma in una crisi si può sempre usare la forza bruta ... (sono sicuro che si può ignorare i risultati reali?)

std::string rslt; 
{ 
    std::stringstream ss; 
    ss << variable; // use same formatting as in your example 

    size_t minusSignIndx = ss.str().find("-0.00"); 

    if (minusSignIndx != std::string::npos) 
     rslt = " 0.00"; // found the nasty, ignore it 
    else 
     rslt = ss.str(); // not nasty, use it 
} 
//... use rslt 
+0

puoi spiegare perché hai usato 'find' invece di' if (ss.str() == "-0.00") ' –

+0

@ M.M - no. Il pensiero minimo era coinvolto. Il confronto ha il vantaggio. –

0

Il problema è che ogni virgola mobile in un certo intervallo [basso, -0,0] sarà essere stampato "-0,00".

Quindi devi trovare basso:

  • tale che la stampa (predecessore (basso)) => "-0.01"
  • tale che la stampa (basso) => "-0.00"

Poi, sarete in grado di scrivere qualcosa di simile (nan a parte ...)

double filter(double x) { 
    double low = ... ; 
    return (x < low) 
     ? x 
     : ((x > 0.0) 
      ? x 
      : 0.0) ; 
} 

Se si dispone di un printf correttamente arrotondato, e gestire la tua aritmetica deve essere rigorosamente conforme allo standard IEEE754 con i flag appropriati del compilatore, il valore esatto di basso è il doppio più vicino a -1/200, maggiore di -1/200 (scrivo 1/200 piuttosto che -0.005 perché sto parlando del valore decimale, non il doppio)

Quello che abbiamo con sscanf arrotondato correttamente ("- 0.005", "% lf", d): il doppio risultato è inferiore a -1/200. Ho fatto controllare che con l'aritmetica esatta come per esempio si trovano in Pharo linguaggio Smalltalk:

[-0.005 < (-1/200) and: [-0.005 successor > (-1/200)]] assert. 

Il suo successore è maggiore di -1/200 (necessariamente, al di sopra di controllo è solo foolproofing).

Così si può scrivere (notare la < = basso):

double filter(double x) { 
    double low = 0.005 ; 
    return (x <= low) 
     ? x 
     : ((x > 0.0) 
      ? x 
      : 0.0) ; 
}