Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cstddev.cc @ a3be1d55

History | View | Annotate | Download (9.67 KB)

1 01873262 Georg Kunz
//=========================================================================
2
//  CSTDDEV.CC - part of
3
//
4
//                  OMNeT++/OMNEST
5
//           Discrete System Simulation in C++
6
//
7
//        Based on the MISS simulator's result collection
8
//
9
//   Member functions of
10
//    cStdDev: basic statistics (mean, stddev, min, max, etc)
11
//    cWeightedStdDev: weighted version
12
//
13
//  Author: Andras Varga
14
//
15
//=========================================================================
16
17
/*--------------------------------------------------------------*
18
  Copyright (C) 1992-2008 Andras Varga
19
  Copyright (C) 2006-2008 OpenSim Ltd.
20

21
  This file is distributed WITHOUT ANY WARRANTY. See the file
22
  `license' for details on this and other legal matters.
23
*--------------------------------------------------------------*/
24
25
#include <stdio.h>
26
#include <string.h>
27
#include <math.h>
28
#include <string>
29
30
#include "cstddev.h"
31
#include "random.h"
32
#include "distrib.h"
33
#include "globals.h"
34
#include "cdetect.h"  //NL
35
#include "csimplemodule.h"
36
#include "cexception.h"
37
#include "cenvir.h"
38
#include "stringutil.h"
39
40
#ifdef WITH_PARSIM
41
#include "ccommbuffer.h"
42
#endif
43
44
USING_NAMESPACE
45
46
using std::ostream;
47
48
Register_Class(cStdDev);
49
Register_Class(cWeightedStdDev);
50
51
52
cStdDev::cStdDev(const char *s) : cStatistic(s)
53
{
54
    num_vals = 0L;
55
    sum_vals = sqrsum_vals = 0;
56
    min_vals = max_vals= 0;
57
}
58
59
std::string cStdDev::info() const
60
{
61
    std::stringstream out;
62
    out << "n=" << getCount()
63
        << " mean=" << getMean()
64
        << " stddev=" << getStddev()
65
        << " min=" << getMin()
66
        << " max=" << getMax();
67
    return out.str();
68
}
69
70
void cStdDev::parsimPack(cCommBuffer *buffer)
71
{
72
#ifndef WITH_PARSIM
73
    throw cRuntimeError(this,eNOPARSIM);
74
#else
75
    cStatistic::parsimPack(buffer);
76
    buffer->pack(num_vals);
77
    buffer->pack(min_vals);
78
    buffer->pack(max_vals);
79
    buffer->pack(sum_vals);
80
    buffer->pack(sqrsum_vals);
81
#endif
82
}
83
84
void cStdDev::parsimUnpack(cCommBuffer *buffer)
85
{
86
#ifndef WITH_PARSIM
87
    throw cRuntimeError(this,eNOPARSIM);
88
#else
89
    cStatistic::parsimUnpack(buffer);
90
    buffer->unpack(num_vals);
91
    buffer->unpack(min_vals);
92
    buffer->unpack(max_vals);
93
    buffer->unpack(sum_vals);
94
    buffer->unpack(sqrsum_vals);
95
#endif
96
}
97
98
cStdDev& cStdDev::operator=(const cStdDev& res)
99
{
100
    if (this==&res) return *this;
101
102
    cStatistic::operator=(res);
103
    num_vals = res.num_vals;
104
    min_vals = res.min_vals;
105
    max_vals = res.max_vals;
106
    sum_vals = res.sum_vals;
107
    sqrsum_vals = res.sqrsum_vals;
108
109
    return *this;
110
}
111
112
void cStdDev::collect(double value)
113
{
114
    if (++num_vals <= 0)
115
    {
116
        // num_vals overflow: issue warning and stop collecting
117
        ev.printf("\a\nWARNING: (%s)%s: collect(): observation count overflow!\n\n",getClassName(),getFullPath().c_str());
118
        num_vals--;  // restore
119
        return;
120
    }
121

122
    sum_vals += value;
123
    sqrsum_vals += value*value;
124

125
    if (num_vals > 1)
126
    {
127
        if (value < min_vals)
128
            min_vals = value;
129
        else if (value > max_vals)
130
            max_vals = value;
131
    }
132
    else
133
    {
134
        min_vals = max_vals = value;
135
    }
136

137
    if (getTransientDetectionObject()) td->collect(value);  //NL
138
    if (getAccuracyDetectionObject()) ra->collect(value);   //NL
139
}
140

141
void cStdDev::doMerge(const cStatistic *other)
142
{
143
    long orig_num_vals = num_vals;
144
    num_vals += other->getCount();
145
    if (num_vals < 0)
146
        throw cRuntimeError(this, "merge(): observation count overflow");
147

148
    if (other->getCount()>0 && (orig_num_vals==0 || min_vals>other->getMin()))
149
        min_vals = other->getMin();
150
    if (other->getCount()>0 && (orig_num_vals==0 || max_vals<other->getMax()))
151
        max_vals = other->getMax();
152

153
    sum_vals += other->getSum();
154
    sqrsum_vals += other->getSqrSum();
155
}
156

157
void cStdDev::merge(const cStatistic *other)
158
{
159
    if (other->isWeighted())
160
        throw cRuntimeError(this, "Cannot merge weighted statistics (%s)%s into unweighted statistics",
161
                                  other->getClassName(), other->getFullPath().c_str());
162
    doMerge(other);
163
}
164

165
double cStdDev::getVariance() const
166
{
167
    if (num_vals <= 1)
168
        return NaN;
169
    else
170
    {
171
        // note: no check for division by zero, we prefer to return Inf or NaN
172
        double devsqr = (sqrsum_vals - sum_vals*sum_vals/num_vals)/(num_vals-1);
173
        return devsqr<0 ? 0 : devsqr;
174
    }
175
}
176

177
double cStdDev::getStddev() const
178
{
179
    return sqrt(getVariance());
180
}
181

182
std::string cStdDev::detailedInfo() const
183
{
184
    std::stringstream os;
185
    os <<   "  Number of values = " << num_vals << "\n";
186
    if (num_vals==1)
187
        os << "  Value          = " << min_vals << "\n";
188
    else if (num_vals>0)
189
    {
190
        os << "  Mean value     = " << getMean() << "\n";
191
        os << "  Standard dev.  = " << getStddev() << "\n";
192
        os << "  Minimal value  = " << min_vals << "\n";
193
        os << "  Maximal value  = " << max_vals << "\n";
194
    }
195
    return os.str();
196
}
197

198
void cStdDev::clearResult()
199
{
200
    num_vals=0;
201
    sum_vals=sqrsum_vals=min_vals=max_vals=0;
202
}
203

204
double cStdDev::random() const
205
{
206
    switch (num_vals)
207
    {
208
        case 0:  return 0.0;
209
        case 1:  return min_vals;
210
        default: return normal(getMean(), getStddev(), genk);
211
    }
212
}
213

214
void cStdDev::saveToFile(FILE *f) const
215
{
216
    fprintf(f,"\n#\n# (%s) %s\n#\n", getClassName(), getFullPath().c_str());
217
    fprintf(f,"%ld\t #= num_vals\n",num_vals);
218
    fprintf(f,"%g %g\t #= min, max\n", min_vals, max_vals);
219
    fprintf(f,"%g\t #= sum\n", sum_vals);
220
    fprintf(f,"%g\t #= square sum\n", sqrsum_vals );
221
}
222

223
void cStdDev::loadFromFile(FILE *f)
224
{
225
    freadvarsf(f,"");  freadvarsf(f,""); freadvarsf(f,""); freadvarsf(f,"");
226
    freadvarsf(f,"%ld\t #= num_vals",&num_vals);
227
    freadvarsf(f,"%g %g\t #= min, max", &min_vals, &max_vals);
228
    freadvarsf(f,"%g\t #= sum", &sum_vals);
229
    freadvarsf(f,"%g\t #= square sum", &sqrsum_vals);
230
}
231

232
//----
233

234
std::string cWeightedStdDev::info() const
235
{
236
    std::stringstream out;
237
    out << "n=" << getCount()
238
        << " mean=" << getMean()
239
        << " stddev=" << getStddev()
240
        << " min=" << getMin()
241
        << " max=" << getMax();
242
    return out.str();
243
}
244

245
void cWeightedStdDev::parsimPack(cCommBuffer *buffer)
246
{
247
#ifndef WITH_PARSIM
248
    throw cRuntimeError(this,eNOPARSIM);
249
#else
250
    cStdDev::parsimPack(buffer);
251
    buffer->pack(sum_weights);
252
    buffer->pack(sum_weighted_vals);
253
    buffer->pack(sum_squared_weights);
254
    buffer->pack(sum_weights_squared_vals);
255
#endif
256
}
257

258
void cWeightedStdDev::parsimUnpack(cCommBuffer *buffer)
259
{
260
#ifndef WITH_PARSIM
261
    throw cRuntimeError(this,eNOPARSIM);
262
#else
263
    cStdDev::parsimUnpack(buffer);
264
    buffer->unpack(sum_weights);
265
    buffer->unpack(sum_weighted_vals);
266
    buffer->unpack(sum_squared_weights);
267
    buffer->unpack(sum_weights_squared_vals);
268
#endif
269
}
270

271
cWeightedStdDev& cWeightedStdDev::operator=(const cWeightedStdDev& res)
272
{
273
    if (this==&res) return *this;
274

275
    cStdDev::operator=(res);
276
    sum_weights = res.sum_weights;
277
    sum_weighted_vals = res.sum_weighted_vals;
278
    sum_squared_weights = res.sum_squared_weights;
279
    sum_weights_squared_vals = res.sum_weights_squared_vals;
280
    return *this;
281
}
282

283
void cWeightedStdDev::collect2(double value, double weight)
284
{
285
    if (weight > 0)
286
    {
287
        if (++num_vals <= 0)
288
        {
289
            // num_vals overflow: issue warning and stop collecting
290
            ev.printf("\a\nWARNING: (%s)%s: collect2(): observation count overflow!\n\n",getClassName(),getFullPath().c_str());
291
            num_vals--;  // restore
292
            return;
293
        }
294

295
        sum_vals += value;
296
        sqrsum_vals += value*value;
297

298
        if (num_vals > 1)
299
        {
300
            if (value < min_vals)
301
                min_vals = value;
302
            else if (value > max_vals)
303
                max_vals = value;
304
        }
305
        else
306
        {
307
            min_vals = max_vals = value;
308
        }
309

310
        sum_weights += weight;
311
        sum_weighted_vals += weight * value;
312
        sum_squared_weights += weight * weight;
313
        sum_weights_squared_vals += weight * value * value;
314

315
        if (getTransientDetectionObject()) td->collect(value);
316
        if (getAccuracyDetectionObject()) ra->collect(value);
317
    }
318
    else if (weight < 0)
319
    {
320
        throw cRuntimeError(this, "collect2(): negative weight %g", weight);
321
    }
322
}
323

324
void cWeightedStdDev::merge(const cStatistic *other)
325
{
326
    cStdDev::doMerge(other);
327
    sum_weights += other->getWeights();
328
    sum_weighted_vals += other->getWeightedSum();
329
    sum_squared_weights += other->getSqrSumWeights();
330
    sum_weights_squared_vals += other->getWeightedSqrSum();
331
}
332

333
void cWeightedStdDev::clearResult()
334
{
335
    cStdDev::clearResult();
336
    sum_weights = 0.0;
337
    sum_weighted_vals = 0.0;
338
    sum_squared_weights = 0.0;
339
    sum_weights_squared_vals = 0.0;
340
}
341

342
double cWeightedStdDev::getVariance() const
343
{
344
    if (num_vals <= 1)
345
        return NaN;
346
    else
347
    {
348
        // note: no check for division by zero, we prefer to return Inf or NaN
349
        double denominator = sum_weights * sum_weights - sum_squared_weights;
350
        double var = (sum_weights * sum_weights_squared_vals - sum_weighted_vals * sum_weighted_vals) / denominator;
351
        return var<0 ? 0 : var;
352
    }
353
}
354

355
void cWeightedStdDev::saveToFile(FILE *f) const
356
{
357
    cStdDev::saveToFile(f);
358
    fprintf(f,"%g\t #= sum_weights\n", sum_weights);
359
    fprintf(f,"%g\t #= sum_weighted_vals\n", sum_weighted_vals);
360
    fprintf(f,"%g\t #= sum_squared_weights\n", sum_squared_weights);
361
    fprintf(f,"%g\t #= sum_weights_squared_vals\n", sum_weights_squared_vals);
362
}
363

364
void cWeightedStdDev::loadFromFile(FILE *f)
365
{
366
    cStdDev::loadFromFile(f);
367
    freadvarsf(f,"%g\t #= sum_weights", &sum_weights);
368
    freadvarsf(f,"%g\t #= sum_weighted_vals", &sum_weighted_vals);
369
    freadvarsf(f,"%g\t #= sum_squared_weights", &sum_squared_weights);
370
    freadvarsf(f,"%g\t #= sum_weights_squared_vals", &sum_weights_squared_vals);
371
}
372

373