2015-05-19 11 views
6

In un programma C++, voglio visualizzare una colonna di valori in virgola mobile in modo che il segno, le cifre e il punto decimale siano allineati. Più zeri iniziali dovrebbero coprire l'intera parte numerica di ciascun valore, quando necessario. Ad esempio:Come visualizzare più zeri iniziali per i valori in virgola mobile in C++?

A column of floating point values: 
    +000.0012 
    -000.
    +000.1235 
    -001.2346 
    +012.3457 
    -123.4568 

Ho avuto un programma di test dettagliatamente commentato che ha dimostrato il problema. Ma, come stavo scrivendo questo post, ho trovato la risposta che ho bisogno qui:
- Extra leading zeros when printing float using printf?

Il problema essenziale era che stavo usando un codice di formato di "%+04.4f" quando dovrei usare "%+09.4f", perché il totale larghezza del campo I voglio è 9:

  • 1 per il segno
  • 3 per l'intero cifre
  • 1 per il punto
  • 4 decimali per le cifre frazionarie

Non ho abbastanza punti reputazione per commentare quel post, quindi grazie da qui, @AndiDog.

Ancora non so come ottenere più zeri iniziali utilizzando solo flag di formattazione dello stream. Ma questa è una battaglia per un altro giorno. Per ora rimarrò con una miscela di printf e stream.

+0

vedere: http://stackoverflow.com/questions/1714515/how-can-i-pad-an-int-with-leading-zeros-when-using-cout-operator – NathanOliver

+2

use std :: setfill (' 0 ') e std :: setw() – 911

+0

Non penso che 'setfilll' funzionerà in questo caso. Usando '0' come carattere di riempimento, il suo primo risultato finirebbe come' 00 + 0.0012', invece di '+' precedendo tutte le cifre come desiderato. –

risposta

8

Un paio di commenti hanno menzionato std::setfill('0') e std::setw. Mentre questi sono necessari, non sono sufficienti per l'attività. Ad esempio, questo codice:

std::cout << std::setfill('0') << std::setw(7) << std::showpos << 0.012; 

produrrà: 0+0.012 come uscita. Questo ovviamente non è esattamente quello che volevamo.

Abbiamo bisogno di aggiungere il flag std::internal per indicare allo stream di inserire "padding interno" - ad es., L'imbottitura deve essere inserito tra il segno e il resto del numero, quindi il codice come questo:

std::cout << std::setfill('0') << std::setw(7) << std::internal << std::showpos << 0.012; 

... produce l'uscita che vogliamo: +00.012.

Si noti inoltre che il carattere di riempimento è "appiccicoso", quindi se si alterna l'utilizzo di std::setw con tipi numerici e non numerici, sarà probabilmente necessario/si desidera cambiarlo ogni volta. In caso contrario, qualcosa come std::cout << setw(12) << name; produrrà risultati come: 0000000Jerry, che è raramente desiderato.

per assicurare che otteniamo sempre lo stesso numero di posti dopo la virgola, abbiamo anche bisogno di impostare il flag std::fixed, e specificare il numero di posti con std::setprecision, come ad esempio:

#include <iostream> 
#include <iomanip> 
#include <vector> 

int main() { 
    std::vector<double> values { 0.1234, 1.234, 1.5555 }; 

    for (auto d : values) 
     std::cout << std::internal << std::showpos << std::setw(9) 
        << std::setprecision(3) << std::setfill('0') << d << "\n"; 
} 

che produce l'uscita credo che si desidera:

+0000.123 
+0001.234 
+0001.556 

C'è una circostanza in cui non sarà possibile ottenere risultati allineati in questo modo però: se si dispone di un numero troppo grande per entrare nel campo fornito, tutti i luoghi prima della decim al punto verrà comunque stampato. Ad esempio, se abbiamo aggiunto 1e10 all'elenco di numeri da stampare con il codice precedente, questo verrà stampato come: +10000000000.000, che ovviamente non sarà allineato con il resto.

Il modo ovvio di affrontarlo sarebbe quello di sopportarlo e, se si presenta abbastanza spesso da preoccuparsi, aumentare le dimensioni del campo per accogliere i numeri più grandi.

Un'altra possibilità sarebbe quella di utilizzare la notazione fissa solo il numero è al di sotto di una certa soglia e passare alla notazione scientifica (per esempio) per numeri più grandi.

Almeno nella mia esperienza, il codice come questo tende ad essere utilizzato principalmente per dati finanziari, nel qual caso quest'ultima opzione di solito non è accettabile.

3

Per mostrare il segno positivo, si utilizza std :: showpos.

Per mostrare gli zeri iniziali, si utilizzano std :: setw (n) e std :: setfill ('0').

Per visualizzare le cifre dopo zero, si utilizza std :: setprecision (m).

Per mostrare gli zeri tra il segno + e la prima cifra, si utilizza std :: internal.

Per mantenere la cifra in una posizione fissa, utilizzare std :: fixed.

#include <iostream>  // std::cout, std::fixed 
#include <iomanip>  // std::setprecision 

int main() { 
    double f =1.234; 
    double g =-12.234; 
    std::cout << std::showpos<< std::internal << std::fixed << std::setprecision(4)<<std::setw(9) <<std::setfill('0') << f << '\n'; 
    std::cout <<std::setw(9)<< std::setfill('0') <<g<<"\n"; //repeat these for a new number 
    return 0; 
    } 


//output: 
//+001.2340 
//-012.2340 
+0

Il codice stampa '000 + 1.234' – hyde

+0

dovresti usare std :: fixed per mostrare gli zeri iniziali. La linea di stampa diventerebbe: std :: cout << std :: showpos << std :: fixed << std :: setprecision (4) << std :: setw (9) << std :: setfill ('0 ') << f <<' \ n '; –

+1

my bad, hai anche bisogno di std :: internal. Ora modificherò l'esempio. –

0

L'unico modo che ora come farlo è quello di visualizzare il segno e poi impostare il riempimento, la larghezza e la precisione dopo e visualizzare il valore positivo, come si è già visualizzato il segno. È inoltre necessario impostare il flag formato ios::fixed

#include <iostream> 
#include <iomanip> 
using namespace std; 

int main() 
{ 
    float x[] = { 000.0012, .0123, .1235, 1.2346, 12.3457, 123.4568 }; 
    cout.setf(ios::fixed); 
    for (int i = 0; i < 6; i++) 
     cout << (x[i] > 0 ? '+' : '-') << setfill('0') << setw(8) << setprecision(4) << abs(x[i]) << endl; 
    return 0; 
} 

Displays

+000.0012 
-000.
+000.1235 
-001.2346 
+012.3457 
-123.4568 
+0

Questo non è "l'unico modo". Guarda le altre risposte –

+0

@CaioOliveira Non ho mai detto che è l'unico modo. Solo l'unico modo che conoscevo al momento in cui ho scritto questo. – NathanOliver

Problemi correlati