libatomprobe
Library for Atom Probe Tomography (APT) computation
lfsr.cpp
Go to the documentation of this file.
1 /* lsfr.cpp : Linear shift feedback register
2  * Copyright (C) 2017 Daniel Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
20 
21 namespace AtomProbe
22 {
23 
24 //For the table to work, we need the sizeof(size_T) at preprocess time
25 #ifndef SIZEOF_SIZE_T
26 #error sizeof(size_t) macro is undefined... At time of writing, this is usually 4 (32 bit) or 8. You can work it out from a simple C++ program which prints out sizeof(size_t). This cant be done automatically due to preprocessor behaviour.
27 #endif
28 
29 //Maximum period linear shift register values (computed by
30 //other program for Galois polynomial)
31 //Unless otherwise noted, all these entries have been verified using the
32 //verifyTable routine.
33 //
34 //If you don't trust me, (who doesn't trust some random person on the internet?)
35 //you can re-run the verification routine.
36 //
37 //Note that verification time *doubles* with every entry, so full 64-bit verification
38 //is computationally intensive. I achieved 40 bits in half a day. 48 bits took over a week.
39 const size_t maximumLinearTable[] = {
40  0x03,
41  0x06,
42  0x0C,
43  0x14,
44  0x30,
45  0x60,
46  0xb8,
47  0x0110,
48  0x0240,
49  0x0500,
50  0x0e08,
51  0x1c80,
52  0x3802,
53  0x6000,
54  0xb400,
55  0x12000,
56  0x20400,
57  0x72000,
58  0x90000,
59  0x140000,
60  0x300000,
61  0x420000,
62  0xD80000,
63  0x1200000,
64  0x3880000,
65  0x7200000,
66  0x9000000,
67  0x14000000,
68  0x32800000,
69  0x48000000,
70 
71 #if (SIZEOF_SIZE_T > 4)
72  0xA3000000,
73  0x100080000,
74  0x262000000,
75  0x500000000,
76  0x801000000,
77  0x1940000000,
78  0x3180000000,
79  0x4400000000,
80  0x9C00000000,
81  0x12000000000,
82  0x29400000000,
83  0x63000000000,
84  0xA6000000000,
85  0x1B0000000000,
86  0x20E000000000,
87  0x420000000000,
88  0x894000000000,
89  //Maximal linear table entries below line are unverified
90  //Verifying the full table might take a few months of computing time
91  //But who needs to count beyond 2^49-1 (~10^14) anyway??
92  0x1008000000000,
93 
94  //Really, there are more entries beyond this, but I consider it pretty much not worth the effort.
95 #endif
96 };
97 
98 void LinearFeedbackShiftReg::setMaskPeriod(unsigned int newMask)
99 {
100  //Don't fall off the table
101  ASSERT((newMask-3) < sizeof(maximumLinearTable)/sizeof(size_t));
102 
103  maskVal=maximumLinearTable[newMask-3];
104 
105  //Set the mask to be all ones
106  totalMask=0;
107  for(size_t ui=0;ui<newMask;ui++)
108  totalMask|= (size_t)(1)<<ui;
109 
110 
111 }
112 
114 {
115  size_t tableLen = sizeof(maximumLinearTable)/sizeof(size_t);
116 
117  //check each one is actually the full 2^n-1 period
118  if(maxLen)
119  {
120  ASSERT(maxLen < tableLen);
121  tableLen=maxLen;
122  }
123 
124  //For the 32 bit table, this works pretty quickly.
125  //for the 64 bit table, this takes a month or so
126  //The test here is a little weak, all it tests is that the return to
127  // 1 is such that there are enough visitations to visit each number exactly once
128  // no more no less. However, it doesn't check each number is actually visited,
129  // as this would be memory intensive
130  for(size_t n=3;n<tableLen+3;n++)
131  {
132  size_t period;
133  setState(1);
134  setMaskPeriod(n);
135  period=0;
136  do
137  {
138  clock();
139  period++;
140  }
141  while(lfsr!=1);
142 
143 
144  //we should have counted every bit position in the polynomial (except 0)
145  //otherwise, this is not the maximal linear sequence
146  if(period != ((size_t)(1)<<(n-(size_t)1)) -(size_t)(1))
147  return false;
148  }
149  return true;
150 }
151 
153 {
154  typedef size_t ull;
155 
156  lfsr = (lfsr >> 1) ^ ( (-(lfsr & (ull)(1u))) & maskVal );
157  lfsr&=totalMask;
158  if( lfsr == 0u)
159  lfsr=1u;
160 
161  return lfsr;
162 }
163 
164 }
void setState(size_t newState)
Set the internal lfsr state. Note 0 is the lock-up state.
Definition: lfsr.h:39
void setMaskPeriod(unsigned int newMask)
Set the mask to use such that the period is 2^n-1. 3 is minimum 60 is maximum.
Definition: lfsr.cpp:98
size_t clock()
Get a value from the shift register, and advance.
Definition: lfsr.cpp:152
#define ASSERT(f)
const size_t maximumLinearTable[]
Definition: lfsr.cpp:39
bool verifyTable(size_t maxLen=0)
Check the validity of the table.
Definition: lfsr.cpp:113