1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <cassert>
using namespace std;
const char *argv0;
void usage(){
cerr<<"Usage: "<<argv0<<" [<lowbound> <highbound>] [<nbins>]"<<endl
<<"Prints a simple histogram of stdin data in your terminal, using"<<endl
<<"either the given lower and upper bounds, or the minimum and"<<endl
<<"maximum extracted from the data."<<endl
<<"The number of bins can also be passed."<<endl
<<"Data on stdin is assumed to be a list of floating-point values."<<endl;
}
double parsefloat(const char *s,const char *errprefix){
char *endp;
double v=strtod(s,&endp);
if(!s[0]||*endp){
cerr<<errprefix<<" '"<<s<<"'"<<endl;
usage();
exit(1);
}
return v;
}
int parseint(const char *s,const char *errprefix){
char *endp;
int v=strtol(s,&endp,10);
if(!s[0]||*endp){
cerr<<errprefix<<" '"<<s<<"'"<<endl;
usage();
exit(1);
}
return v;
}
int main(int argc,char **argv){
argv0=argv[0];
const int BARWIDTH=80;
double low,high;
bool havebounds;
int nbins=10;
if(argc==1){
havebounds=false;
} else if(argc==2){
havebounds=false;
nbins=parseint(argv[1],"Invalid number");
} else if(argc==3){
havebounds=true;
low=parsefloat(argv[1],"Invalid number");
high=parsefloat(argv[2],"Invalid number");
} else if(argc==4){
havebounds=true;
low=parsefloat(argv[1],"Invalid number");
high=parsefloat(argv[2],"Invalid number");
nbins=parseint(argv[3],"Invalid number");
} else {
usage();
return 1;
}
if(nbins<1){
cerr<<"Invalid number of bins '"<<nbins<<"'"<<endl;
usage();
return 1;
}
double minval=INFINITY,maxval=-INFINITY;
vector<double> values;
while(true){
double v;
cin>>v;
if(!cin)break;
values.push_back(v);
if(v<minval)minval=v;
if(v>maxval)maxval=v;
}
if(!havebounds){
low=minval;
high=maxval;
}
sort(values.begin(),values.end());
vector<int> histogram(nbins);
int binidx=0,tally=0,maxtally=-1;
for(double v : values){
if(v<low||v>high){
// cerr<<"Point "<<v<<" out of range!"<<endl;
continue;
}
int bin=(v-low)/(high-low)*nbins;
if(bin==nbins)bin--;
assert(bin>=0&&bin<nbins);
if(bin!=binidx){
histogram[binidx]=tally;
if(tally>maxtally)maxtally=tally;
binidx=bin;
tally=0;
}
tally++;
}
histogram[binidx]=tally;
if(tally>maxtally)maxtally=tally;
char fullbar[BARWIDTH+1];
memset(fullbar,'#',BARWIDTH);
fullbar[BARWIDTH]='\0';
char emptybar[BARWIDTH+1];
memset(emptybar,' ',BARWIDTH);
emptybar[BARWIDTH]='\0';
for(int i=0;i<(int)histogram.size();i++){
int tally=histogram[i];
int width=BARWIDTH*tally/maxtally;
cout<<fullbar+BARWIDTH-width<<emptybar+width
<<" ("<<setw(11)<<low+(double)i/nbins*(high-low)<<" - "<<setw(11)<<low+(double)(i+1)/nbins*(high-low)<<")"
<<" ["<<tally<<"]"<<endl;
}
}
|