-
Notifications
You must be signed in to change notification settings - Fork 0
/
DetectorTypeC.cxx
146 lines (124 loc) · 3.24 KB
/
DetectorTypeC.cxx
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Parallel Podd DetectorTypeC
//
// Simple "detector" class, doing computation of pi as an example
// of a time-consuming task
#include "DetectorTypeC.h"
#include "Podd.h"
#include "Decoder.h"
#include "Database.h"
#include <cstdlib>
#include <stdexcept>
//#include <cassert>
using namespace std;
DetectorTypeC::DetectorTypeC( const string& name, int imod )
: Detector(name, imod), m_ndig(0), m_last5(0), m_scale(1.0)
{
type = "C";
m_result.reserve(5000);
}
DetectorTypeC::~DetectorTypeC()
{
DetectorTypeC::DefineVariables( kRemove );
}
void DetectorTypeC::Clear()
{
Detector::Clear();
m_result.clear();
m_ndig = 0;
m_last5 = 0;
}
unique_ptr<Detector> DetectorTypeC::Clone() const
{
return make_unique<DetectorTypeC>(*this);
}
int DetectorTypeC::Analyze()
{
// This detector type computes n digits of pi
//
// Attempts to implement the algorithm from
// Rabinowitz and Wagon, "A spigot algorithm for the digits of Pi",
// American Mathematical Monthly, 102 (3), 195–203 (March 1995),
// doi:10.2307/2975006.
//
// Note: There appears to be a bug in this code that sometimes gets the
// last digit wrong. Compare the results for n = 50 and n = 51 for example.
// We ignore this problem here.
int n = 0;
if( !data.empty() )
n = int(data[0]*m_scale);
if( n < 1 )
n = 10;
int N = (10*n)/3;
m_a.assign(N,2);
m_result.reserve(n+1);
int last_digit = -1;
int nines = 0;
bool dot = true;
for( int i = 0; i < n; i++ ) {
for( int j = 0; j < N; j++ )
m_a[j] *= 10;
for( int j = N-1; j > 0; j-- ) {
div_t d = div(m_a[j],2*j+1);
m_a[j] = d.rem;
m_a[j-1] += d.quot*j;
}
int Q = m_a[0]/10;
m_a[0] -= 10*Q;
if( Q < 9 ) {
if( last_digit >= 0 )
m_result += char('0'+last_digit);
if( dot && last_digit >= 0 ) {
dot = false;
m_result += '.';
}
for( int j = 0; j < nines; j++ )
m_result += '9';
nines = 0;
last_digit = Q;
} else if ( Q == 9 ) {
nines ++;
} else if ( Q == 10 ) {
if( last_digit >= 0 )
m_result += char('1'+last_digit);
if( dot && last_digit >= 0 ) {
dot = false;
m_result += '.';
}
for( int j = 0; j < nines; j++ )
m_result += '0';
nines = 0;
last_digit = 0;
}
}
if( last_digit >= 0 )
m_result += char('0'+last_digit);
//assert( m_result.length() == n+1 ); // This sometimes trips, exposing the bug mentioned above
m_ndig = n;
m_last5 = std::stod(m_result.substr(m_result.length() - 5, 5));
return 0;
}
void DetectorTypeC::Print() const
{
Detector::Print();
}
int DetectorTypeC::DefineVariables( bool do_remove )
{
const vector<VarDef_t> defs = {
{"nval", "Number of digits computed", &m_ndig},
{"last8", "Value of last 5 digits", &m_last5},
};
return DefineVarsFromList(defs, GetName(), fVars, do_remove);
}
int DetectorTypeC::ReadDatabase( bool shared )
{
int status = Detector::ReadDatabase(shared);
if( status )
return status;
if( shared ) {
// See if the database contains the key "detC.scale".
// If so, assign its value to m_scale. Otherwise m_scale = 1.0
auto val = database.Get("scale", name);
m_scale = val.value_or(1.0);
}
return 0;
}