After going over this tutorial
http://tommd.github.io/
which uses the HElib library:
https://github.com/shaih/HElib
I get the following output:
The output is getting corrupted. Given that the example has Level 16, there should be plenty of room to perform these operations.
Is there a problem with the parameters ?
Code:
#include "FHE.h"
#include "EncryptedArray.h"
#include <NTL/lzz_pXFactoring.h>
#include <fstream>
#include <sstream>
#include <sys/time.h>
using namespace std;
/**
*
*/
int main(int argc, char** argv) {
/* On our trusted system we generate a new key
* (or read one in) and encrypt the secret data set.
*/
long m=0, p=2, r=1; // Native plaintext space
// Computations will be 'modulo p'
long L=16; // Levels
long c=3; // Columns in key switching matrix
long w=64; // Hamming weight of secret key
long d=0;
long security = 128;
ZZX G;
m = FindM(security,L,c,p, d, 0, 0);
FHEcontext context(m, p, r);
// initialize context
buildModChain(context, L, c);
// modify the context, adding primes to the modulus chain
FHESecKey secretKey(context);
// construct a secret key structure
const FHEPubKey& publicKey = secretKey;
// an "upcast": FHESecKey is a subclass of FHEPubKey
//if(0 == d)
G = context.alMod.getFactorsOverZZ()[0];
secretKey.GenSecKey(w);
// actually generate a secret key with Hamming weight w
addSome1DMatrices(secretKey);
cout << "Generated key" << endl;
EncryptedArray ea(context, G);
// constuct an Encrypted array object ea that is
// associated with the given context and the polynomial G
long nslots = ea.size();
vector<long> v1;
for(int i = 0 ; i < nslots; i++) {
v1.push_back(i*2);
}
Ctxt ct1(publicKey);
ea.encrypt(ct1, publicKey, v1);
vector<long> v2;
Ctxt ct2(publicKey);
for(int i = 0 ; i < nslots; i++) {
v2.push_back(i*3);
}
ea.encrypt(ct2, publicKey, v2);
// On the public (untrusted) system we
// can now perform our computation
Ctxt ctSum = ct1;
Ctxt ctProd = ct1;
ctSum += ct2;
ctProd *= ct2;
vector<long> res;
ea.decrypt(ctSum, secretKey, res);
cout << "All computations are modulo " << p << "." << endl;
for(int i = 0; i < res.size(); i ++) {
cout << v1[i] << " + " << v2[i] << " = " << res[i] << endl;
}
ea.decrypt(ctProd, secretKey, res);
for(int i = 0; i < res.size(); i ++) {
cout << v1[i] << " * " << v2[i] << " = " << res[i] << endl;
}
return 0;
}
Generated key
All computations are modulo 2.
0 + 0 = 0
2 + 3 = 1
4 + 6 = 0
6 + 9 = 1
8 + 12 = 0
10 + 15 = 1
12 + 18 = 0
14 + 21 = 1
16 + 24 = 0
18 + 27 = 1
20 + 30 = 0
22 + 33 = 1
24 + 36 = 0
26 + 39 = 1
28 + 42 = 0
30 + 45 = 1
32 + 48 = 0
34 + 51 = 1
36 + 54 = 0
38 + 57 = 1
40 + 60 = 0
42 + 63 = 1
44 + 66 = 0
46 + 69 = 1
48 + 72 = 0
50 + 75 = 1
52 + 78 = 0
54 + 81 = 1
56 + 84 = 0
58 + 87 = 1
60 + 90 = 0
... Some sum output omitted
0 * 0 = 0
2 * 3 = 0
4 * 6 = 0
6 * 9 = 0
8 * 12 = 0
10 * 15 = 0
12 * 18 = 0
14 * 21 = 0
16 * 24 = 0
18 * 27 = 0
20 * 30 = 0
22 * 33 = 0
24 * 36 = 0
26 * 39 = 0
28 * 42 = 0
30 * 45 = 0
32 * 48 = 0
34 * 51 = 0
36 * 54 = 0
38 * 57 = 0
40 * 60 = 0
42 * 63 = 0
44 * 66 = 0
46 * 69 = 0
48 * 72 = 0
50 * 75 = 0
52 * 78 = 0
54 * 81 = 0
56 * 84 = 0
58 * 87 = 0
60 * 90 = 0
62 * 93 = 0
64 * 96 = 0
66 * 99 = 0
68 * 102 = 0
70 * 105 = 0
72 * 108 = 0
74 * 111 = 0
76 * 114 = 0
78 * 117 = 0
80 * 120 = 0
82 * 123 = 0
84 * 126 = 0
86 * 129 = 0
....
Ah, so this is a misunderstanding of the operations being performed. Notice the constant p=2. I have the text All computations are modulo 2.. Perhaps also stating All inputs are modulo 2 would help hammer the point home. Lets look at some of our computations:
0 + 0 mod 2 = 0
2 + 3 mod 2 = 1
4 + 6 mod 2 = 0
6 + 9 mod 2 = 1
All looks good - addition ring 2 is just exclusive OR. How about multiplication? In ring 2 (binary) that's just AND:
0 * 0 = 0
2 * 3 = 6 mod 2 = 0
4 * 6 = 24 mod 2 = 0
6 * 9 = 54 mod 2 = 0
So that all checks out as well. Finally, look back at the blog and see that I called this out again and give you a way to operate on something you might consider more pleasing:
In this case, I am building for GF(2) - so my homormorphic addition
is XOR and multiplication is AND. Changing this is as easy as changing
the value of p. Folks wanting to see 2+2=4 should set p to something
that matches their desired domain, such as 257 to obtain 8 bit Ints.
However, HELib has regressed in this aspect - setting p equal to anything larger than 2 did not work last time I tried it. Shai confirmed this is a known regression.
Related
I write grid-stride loop to have High Performance Calculations, where large N, for example long long N 1<<36, or even more. From total grid I need only some indexes, which have to satisfy the define condition.
__global__ void Indexes(int *array, int N) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
while( index<N)
{
if (condition)
{....//do something to save index in array}
index += blockDim.x * gridDim.x;
}
}
Of course, it is possible use the Thrust, which allows to have both host and device arrays. But in this case obviously the calculation will be extremely ineffective, because need firstly to create a lot of non-needed elements, then to delete these.
What is the most effective way to save the indexes directly in array in device to pass in CPU?
If your output is relatively dense (i.e. a lot of indices and relatively few zeros), then the stream compaction approach suggested in comments is a good solution. There are a lot of ready-to-go stream compaction implementations which you can probably adapt to your purposes.
If your output is sparse, so you need to save relatively few indices for a lot of inputs, then stream compaction isn't such a great solution because it will waste a lot of GPU memory. In that case (and you can roughly estimate an upper bound of the number of output indices) something like this:
template <typename T>
struct Array
{
T* p;
int Nmax;
int* next;
Array() = default;
__host__ __device__
Array(T* _p, int _Nmax, int* _next) : p(_p), Nmax(_Nmax), next(_next) {};
__device__
int append(T& val)
{
int pos = atomicAdd(next, 1);
if (pos > Nmax) {
atomicExch(next, Nmax);
return -1;
} else {
p[pos] = val;
return pos;
}
};
};
is probably more appropriate. Here, the idea is to use an atomically incremented position in the output array to keep track of where a thread should store its index. The code will signal if you fill the index array, and there will be information from which you can work out a restart strategy to stop the current kernel and then start from the last known index which you were able to store.
A complete example:
$ cat append.cu
#include <iostream>
#include <thrust/device_ptr.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/copy.h>
namespace AppendArray
{
template <typename T>
struct Array
{
T* p;
int Nmax;
int* next;
Array() = default;
__host__ __device__
Array(T* _p, int _Nmax, int* _next) : p(_p), Nmax(_Nmax), next(_next) {};
__device__
int append(T& val)
{
int pos = atomicAdd(next, 1);
if (pos > Nmax) {
atomicExch(next, Nmax);
return -1;
} else {
p[pos] = val;
return pos;
}
};
};
}
__global__
void kernelfind(int* input, int N, AppendArray::Array<int> indices)
{
int idx = threadIdx.x + blockIdx.x * blockDim.x;
for(; idx < N; idx += gridDim.x*blockDim.x) {
if (input[idx] % 10000 == 0) {
if (indices.append(idx) < 0) return;
}
}
}
int main()
{
const int Ninputs = 1 << 20;
thrust::device_vector<int> inputs(Ninputs);
thrust::counting_iterator<int> vals(1);
thrust::copy(vals, vals + Ninputs, inputs.begin());
int* d_input = thrust::raw_pointer_cast(inputs.data());
int Nindices = Ninputs >> 12;
thrust::device_vector<int> indices(Nindices);
int* d_indices = thrust::raw_pointer_cast(indices.data());
int* pos; cudaMallocManaged(&pos, sizeof(int)); *pos = 0;
AppendArray::Array<int> index(d_indices, Nindices-1, pos);
int gridsize, blocksize;
cudaOccupancyMaxPotentialBlockSize(&gridsize, &blocksize, kernelfind, 0, 0);
kernelfind<<<gridsize, blocksize>>>(d_input, Ninputs, index);
cudaDeviceSynchronize();
for(int i = 0; i < *pos; ++i) {
int idx = indices[i];
std::cout << i << " " << idx << " " << inputs[idx] << std::endl;
}
return 0;
}
$ nvcc -std=c++11 -arch=sm_52 -o append append.cu
$ ./append
0 9999 10000
1 19999 20000
2 29999 30000
3 39999 40000
4 49999 50000
5 69999 70000
6 79999 80000
7 59999 60000
8 89999 90000
9 109999 110000
10 99999 100000
11 119999 120000
12 139999 140000
13 129999 130000
14 149999 150000
15 159999 160000
16 169999 170000
17 189999 190000
18 179999 180000
19 199999 200000
20 209999 210000
21 219999 220000
22 239999 240000
23 249999 250000
24 229999 230000
25 279999 280000
26 269999 270000
27 259999 260000
28 319999 320000
29 329999 330000
30 289999 290000
31 299999 300000
32 339999 340000
33 349999 350000
34 309999 310000
35 359999 360000
36 379999 380000
37 399999 400000
38 409999 410000
39 369999 370000
40 429999 430000
41 419999 420000
42 389999 390000
43 439999 440000
44 459999 460000
45 489999 490000
46 479999 480000
47 449999 450000
48 509999 510000
49 539999 540000
50 469999 470000
51 499999 500000
52 569999 570000
53 549999 550000
54 519999 520000
55 589999 590000
56 529999 530000
57 559999 560000
58 619999 620000
59 579999 580000
60 629999 630000
61 669999 670000
62 599999 600000
63 609999 610000
64 699999 700000
65 639999 640000
66 649999 650000
67 719999 720000
68 659999 660000
69 679999 680000
70 749999 750000
71 709999 710000
72 689999 690000
73 729999 730000
74 779999 780000
75 799999 800000
76 809999 810000
77 739999 740000
78 849999 850000
79 759999 760000
80 829999 830000
81 789999 790000
82 769999 770000
83 859999 860000
84 889999 890000
85 879999 880000
86 819999 820000
87 929999 930000
88 869999 870000
89 839999 840000
90 909999 910000
91 939999 940000
92 969999 970000
93 899999 900000
94 979999 980000
95 959999 960000
96 949999 950000
97 1019999 1020000
98 1009999 1010000
99 989999 990000
100 1029999 1030000
101 919999 920000
102 1039999 1040000
103 999999 1000000
The problem: I need to print the Pascal triangle for any (unsigned int) input passed as a command line argument. All the values must be stored in a LINEAR array and elements must only be manipulated as dereferenced pointers. Following this, the array elements must printed as a lower triangular matrix and subsequently deleted. My implementation functions perfectly for input ranging from 0 to 12 but produces spurious results for higher values.
I tried two different implementations.
Declare a pointer to an array of size (n+1)*(n+2)/2 (which is the number of elements in the triangle for input 'n'). Assign/print variables within a nested loop. Delete the pointer once both loops have been executed.
Run a nested loop, 0 <= i <= n, and 0 <= j <= i. Declare a pointer to an array of size (i+1) in the outer loop. Assign/print elements in the inner loop. Delete the pointer once the inner loop has been executed.
// VERSION 1
unsigned N = (n+1)*(n+2)/2;
unsigned* elements = new unsigned[N];
for(i = 0; i <= n; i++) {
for(j = 0; j <= i; j++) {
*(elements + j+(i*i+i)/2) = fact(i) / (fact(j) * fact(i-j));
// print statement
}
cout << endl;
}
delete [] elements;
// VERSION 2
for(i = 0; i <= n; i++) {
unsigned* elements = new unsigned[i+1];
for(j = 0; j <= i; j++) {
*(elements + j) = fact(i) / (fact(j) * fact(i-j));
// print statement
}
delete [] elements;
cout << endl;
}
Both these versions were tried separately on Xcode. In both cases, the triangle printed correctly until the 12th layer, i.e. n=12, but generated incorrect results for higher values.
0 | 1
1 | 1 1
2 | 1 2 1
3 | 1 3 3 1
4 | 1 4 6 4 1
5 | 1 5 10 10 5 1
6 | 1 6 15 20 15 6 1
7 | 1 7 21 35 35 21 7 1
8 | 1 8 28 56 70 56 28 8 1
9 | 1 9 36 84 126 126 84 36 9 1
10 | 1 10 45 120 210 252 210 120 45 10 1
11 | 1 11 55 165 330 462 462 330 165 55 11 1
12 | 1 12 66 220 495 792 924 792 495 220 66 12 1
13 | 1 4 24 88 221 399 532 532 399 221 88 24 4 1
14 | 1 0 1 5 14 29 44 50 44 29 14 5 1 0 1
15 | 1 1 0 0 2 4 7 9 9 7 4 2 0 0 1 1
16 | 1 0 0 0 0 4 0 1 1 1 0 4 0 0 0 0 1
The debugger, to the extent that I can use it, produced no error messages.
What is happening and how do I fix it?
fact(i) overflows really fast. I haven't checked the numbers, but I'm pretty sure that's what's happening.
Instead, use the fact that a number in Pascal's triangle is the sum of the two numbers above it.
Wikipedia has a nice animation for this.
When i is 13, fact(i) is 6227020800, which is too big to fit in a 32-bit unsigned integer, so integer overflow occurs.
A number is called a stepping number if all adjacent digits in the number have an absolute difference of 1.
Examples of stepping numbers :- 0,1,2,3,4,5,6,7,8,9,10,12,21,23,...
I have to generate stepping numbers upto a given number N. The numbers generated should be in order.
I used the simple method of moving over all the numbers upto N and checking if it is stepping number or not. My teacher told me it is brute force and will take more time. Now, I have to optimize my approach.
Any suggestions.
Stepping numbers can be generated using Breadth First Search like approach.
Example to find all the stepping numbers from 0 to N
-> 0 is a stepping Number and it is in the range
so display it.
-> 1 is a Stepping Number, find neighbors of 1 i.e.,
10 and 12 and push them into the queue
How to get 10 and 12?
Here U is 1 and last Digit is also 1
V = 10 + 0 = 10 ( Adding lastDigit - 1 )
V = 10 + 2 = 12 ( Adding lastDigit + 1 )
Then do the same for 10 and 12 this will result into
101, 123, 121 but these Numbers are out of range.
Now any number transformed from 10 and 12 will result
into a number greater than 21 so no need to explore
their neighbors.
-> 2 is a Stepping Number, find neighbors of 2 i.e.
21, 23.
-> generate stepping numbers till N.
The other stepping numbers will be 3, 4, 5, 6, 7, 8, 9.
C++ code to do generate stepping numbers in a given range:
#include<bits/stdc++.h>
using namespace std;
// Prints all stepping numbers reachable from num
// and in range [n, m]
void bfs(int n, int m)
{
// Queue will contain all the stepping Numbers
queue<int> q;
for (int i = 0 ; i <= 9 ; i++)
q.push(i);
while (!q.empty())
{
// Get the front element and pop from the queue
int stepNum = q.front();
q.pop();
// If the Stepping Number is in the range
// [n, m] then display
if (stepNum <= m && stepNum >= n)
cout << stepNum << " ";
// If Stepping Number is 0 or greater than m,
// need to explore the neighbors
if (stepNum == 0 || stepNum > m)
continue;
// Get the last digit of the currently visited
// Stepping Number
int lastDigit = stepNum % 10;
// There can be 2 cases either digit to be
// appended is lastDigit + 1 or lastDigit - 1
int stepNumA = stepNum * 10 + (lastDigit- 1);
int stepNumB = stepNum * 10 + (lastDigit + 1);
// If lastDigit is 0 then only possible digit
// after 0 can be 1 for a Stepping Number
if (lastDigit == 0)
q.push(stepNumB);
//If lastDigit is 9 then only possible
//digit after 9 can be 8 for a Stepping
//Number
else if (lastDigit == 9)
q.push(stepNumA);
else
{
q.push(stepNumA);
q.push(stepNumB);
}
}
}
//Driver program to test above function
int main()
{
int n = 0, m = 99;
// Display Stepping Numbers in the
// range [n,m]
bfs(n,m);
return 0;
}
Visit this link.
The mentioned link has both BFS and DFS approach.
It will provide you with explaination and code in different languages for the above problem.
We also can use simple rules to move to the next stepping number and generate them in order to avoid storing "parents".
C.f. OEIS sequence
#include <iostream>
int next_stepping(int n) {
int left = n / 10;
if (left == 0)
return (n + 1); // 6=>7
int last = n % 10;
int leftlast = left % 10;
if (leftlast - last == 1 & last < 8)
return (n + 2); // 32=>34
int nxt = next_stepping(left);
int nxtlast = nxt % 10;
if (nxtlast == 0)
return (nxt * 10 + 1); // to get 101
return (nxt * 10 + nxtlast - 1); //to get 121
}
int main()
{
int t = 0;
for (int i = 1; i < 126; i++, t = next_stepping(t)) {
std::cout << t << "\t";
if (i % 10 == 0)
std::cout << "\n";
}
}
0 1 2 3 4 5 6 7 8 9
10 12 21 23 32 34 43 45 54 56
65 67 76 78 87 89 98 101 121 123
210 212 232 234 321 323 343 345 432 434
454 456 543 545 565 567 654 656 676 678
765 767 787 789 876 878 898 987 989 1010
1012 1210 1212 1232 1234 2101 2121 2123 2321 2323
2343 2345 3210 3212 3232 3234 3432 3434 3454 3456
4321 4323 4343 4345 4543 4545 4565 4567 5432 5434
5454 5456 5654 5656 5676 5678 6543 6545 6565 6567
6765 6767 6787 6789 7654 7656 7676 7678 7876 7878
7898 8765 8767 8787 8789 8987 8989 9876 9878 9898
10101 10121 10123 12101 12121
def steppingNumbers(self, n, m):
def _solve(v):
if v>m: return 0
ans = 1 if n<=v<=m else 0
last = v%10
if last > 0: ans += _solve(v*10 + last-1)
if last < 9: ans += _solve(v*10 + last+1)
return ans
ans = 0 if n>0 else 1
for i in range(1, 10):
ans += _solve(i)
return ans
#include <iostream>
using namespace std;
void TimesTable(int count)
{
for (int j = 1; j < 13; j++)
{
cout << count << " x " << j << " = " << count*j << " " << endl;
}
}
int main()
{
for (int count = 1; count < 13; count++)
{
TimesTable(count);
cout << endl;
}
system("Pause");
}
This prints
"1 x 1 = 1
1 x 2 = 2
2x1 = 2
2x2 = 4
3x1 = 3
3x2 = 6"
and so on. But the thing I want to do is so instead of having them all print in a line downwards, I want to have it in blocks so,
"1 x 1 = 1 2 x 1 = 2 3 x 1 = 3 4 x 1 = 4 5 x 1 = 5
1 x 2 = 2 2 x 2 = 4 3 x 2 = 6 4 x 2 = 8 5 x 2 = 10"
and so on. But obviously it would look better if it didn't then go to 12 horizontally or otherwise you'd have to grab the bar at the bottom of the console window and drag to see the other timestables. I'd like it so that it went to 5 on block line 1 then on the 2nd line of blocks it would be 6 to 10 and the final line 10 to 12.
Yes it's random that it only goes up to 12 but it was an exercise and I've just adapted it into some other monster.
And I guess I could just have more than one cout in the for loop but I swear in the past I've seen someone do this with just a clever way of passing through a variable so that it printed a block of asterisks side by side instead of pretending to do it.
Desired Result (make it easier with symbols instead):
" ***** ^^^^^ &&&&&
***** ^^^^^ &&&&&
***** ^^^^^ &&&&& "
Result as of now:
" *****
*****
*****
^^^^^
^^^^^
^^^^^
&&&&&
&&&&&
&&&&& "
To format columns, use std::setw from <iomanip>
Sets the field width to be used on output operations.
now.
outside, iterate over the lines.
inside, iterate over the columns.
CODE
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int cols_per_line = 5;
for (int line = 1; line < 13; line++)
{
for (int col = 1; col <= cols_per_line; col++)
{
cout << setw(2) << col << " x " << setw(2) << line << " = " << setw(3) << line*col << " ";
}
cout << endl;
}
}
OUTPUT
[root#rnrlabs ~]# ./a.out
1 x 1 = 1 2 x 1 = 2 3 x 1 = 3 4 x 1 = 4 5 x 1 = 5
1 x 2 = 2 2 x 2 = 4 3 x 2 = 6 4 x 2 = 8 5 x 2 = 10
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9 4 x 3 = 12 5 x 3 = 15
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16 5 x 4 = 20
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45
1 x 10 = 10 2 x 10 = 20 3 x 10 = 30 4 x 10 = 40 5 x 10 = 50
1 x 11 = 11 2 x 11 = 22 3 x 11 = 33 4 x 11 = 44 5 x 11 = 55
1 x 12 = 12 2 x 12 = 24 3 x 12 = 36 4 x 12 = 48 5 x 12 = 60
Just remove the endl at the end of TimeTable for inner "for"
and add another counter for splitter say:
Edit: change j with count.
int splitter = 0;
for (int j = 1; j < 13; j++, splitter++)
{
cout << j << " x " << count << " = " << count*j << "\t";
if (splitter == 5)
{
cout << endl;
splitter=-1;
}
}
1 x 1 = 1 2 x 1 = 2 3 x 1 = 3 4 x 1 = 4 5 x 1 = 5 6 x 1 = 6
7 x 1 = 7 8 x 1 = 8 9 x 1 = 9 10 x 1 = 10 11 x 1 = 11 12 x 1 = 12
1 x 2 = 2 2 x 2 = 4 3 x 2 = 6 4 x 2 = 8 5 x 2 = 10 6 x 2 = 12
7 x 2 = 14 8 x 2 = 16 9 x 2 = 18 10 x 2 = 20 11 x 2 = 22 12 x 2 = 24
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9 4 x 3 = 12 5 x 3 = 15 6 x 3 = 18
7 x 3 = 21 8 x 3 = 24 9 x 3 = 27 10 x 3 = 30 11 x 3 = 33 12 x 3 = 36
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16 5 x 4 = 20 6 x 4 = 24
7 x 4 = 28 8 x 4 = 32 9 x 4 = 36 10 x 4 = 40 11 x 4 = 44 12 x 4 = 48
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25 6 x 5 = 30
7 x 5 = 35 8 x 5 = 40 9 x 5 = 45 10 x 5 = 50 11 x 5 = 55 12 x 5 = 60
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36
7 x 6 = 42 8 x 6 = 48 9 x 6 = 54 10 x 6 = 60 11 x 6 = 66 12 x 6 = 72
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42
7 x 7 = 49 8 x 7 = 56 9 x 7 = 63 10 x 7 = 70 11 x 7 = 77 12 x 7 = 84
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48
7 x 8 = 56 8 x 8 = 64 9 x 8 = 72 10 x 8 = 80 11 x 8 = 88 12 x 8 = 96
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54
7 x 9 = 63 8 x 9 = 72 9 x 9 = 81 10 x 9 = 90 11 x 9 = 99 12 x 9 = 108
1 x 10 = 10 2 x 10 = 20 3 x 10 = 30 4 x 10 = 40 5 x 10 = 50 6 x 10 = 60
7 x 10 = 70 8 x 10 = 80 9 x 10 = 90 10 x 10 = 100 11 x 10 = 110 12 x 10 = 120
1 x 11 = 11 2 x 11 = 22 3 x 11 = 33 4 x 11 = 44 5 x 11 = 55 6 x 11 = 66
7 x 11 = 77 8 x 11 = 88 9 x 11 = 99 10 x 11 = 110 11 x 11 = 121 12 x 11 = 132
1 x 12 = 12 2 x 12 = 24 3 x 12 = 36 4 x 12 = 48 5 x 12 = 60 6 x 12 = 72
7 x 12 = 84 8 x 12 = 96 9 x 12 = 108 10 x 12 = 120 11 x 12 = 132 12 x 12 = 144
First of all, I should state that this is a homework assignment, so while questions that give a direct answer will give me a good grade, I would prefer to know why something doesn't work, and a reason why/how I should fix it with your solution.
So here is the background for this function. I have a quarterback struct with the following information. There are ten games, which all are stored in the struct and its arrays:
struct QuarterBack{
string name;
int completions[kNumGames];
int attempts[kNumGames];
int yards[kNumGames];
int touchdowns[kNumGames];
int interceptions[kNumGames];
};
Now my goal for this problem is to use the information stored in these structs to compute the NFL Style passer ratings. For reference, wikipedia gives the following:
So here is the code I am using. It has some excessive parenthesis that I was trying to use to make sure my control was correct, but other than that I am stumped as to why I am not getting more correct answers. Below the code I will post an example file and output.
/**
* #brief printPasserRating prints the passer rating of all players
* #param players is the array holding all the players
*/
void printPasserRating(QuarterBack *players, int numPlayers){
for(int player = 0; player < numPlayers; player++){
double passerRating = 0;
int sumCompletions = 0, sumAttempts = 0, sumYards = 0,
sumTouchdowns = 0, sumInterceptions = 0;
for(int game = 0; game < kNumGames; game++){
sumCompletions += players[player].completions[game];
sumAttempts += players[player].attempts[game];
sumYards += players[player].yards[game];
sumTouchdowns += players[player].touchdowns[game];
sumInterceptions += players[player].interceptions[game];
}
double a = 0, b = 0, c = 0, d = 0;
double nums[4] = {a, b, c, d};
nums[0] = static_cast<double>((sumCompletions / sumAttempts) - 0.3) * 5;
nums[1] = static_cast<double>((sumYards / sumAttempts) - 3) * 0.25;
nums[2] = static_cast<double>(sumTouchdowns / sumAttempts) * 20;
nums[3] = 2.375 - (static_cast<double>(sumInterceptions / sumAttempts) * 25);
for(int letter = 0; letter < 4; letter++){
nums[letter] = mm(nums[letter]);
}
passerRating = (nums[0] + nums[1] + nums[2] + nums[3]) / 0.06;
cout << players[player].name << "\t" << passerRating << endl;
}
showMenu(players, numPlayers);
}
Here is the example file. Ignore the 4, as it is for a separate part of the problem. Each row is a game, and it is listed as: completions, attempts, yards, touchdowns, then interceptions.
4
Peyton Manning
27 42 462 7 0
30 43 307 2 0
32 37 374 3 0
28 34 327 4 0
33 42 414 4 1
28 42 295 2 1
29 49 386 3 1
30 44 354 4 3
25 36 330 4 0
24 40 323 1 0
Tom Brady
29 52 288 2 1
19 39 185 1 0
25 36 225 2 1
20 31 316 2 0
18 38 197 0 1
25 43 269 1 1
22 46 228 0 1
13 22 116 1 1
23 33 432 4 0
29 40 296 1 1
Drew Brees
26 35 357 2 1
26 46 322 1 2
29 46 342 3 1
30 39 413 4 0
29 35 288 2 0
17 36 236 2 1
26 34 332 5 0
30 51 382 2 2
34 41 392 4 0
30 43 305 1 1
Eli Manning
24 35 360 1 2
25 46 340 2 3
26 44 350 3 1
34 35 460 1 2
25 36 240 2 3
16 34 250 3 1
24 35 360 1 0
35 56 340 2 2
36 44 350 3 0
34 45 360 1 1
And here is the output that the function is giving me:
Any help is much appreciated, and if you need more information to help me, feel free to comment and ask. Also, as this is a homework assignment, don't assume that I am just incompetent even if I make a silly mistake. I was told that Stack Overflow has no stupid questions, and I really hope that the community can live up to that.
This math is unlikely to do what you want:
nums[0] = static_cast<double>((sumCompletions / sumAttempts) - 0.3) * 5;
nums[1] = static_cast<double>((sumYards / sumAttempts) - 3) * 0.25;
nums[2] = static_cast<double>(sumTouchdowns / sumAttempts) * 20;
nums[3] = 2.375 - (static_cast<double>(sumInterceptions / sumAttempts) * 25);
Where you've put the cast will cast the result of the division to be double after the division has been performed. But, the division itself will be an integer division.
You want something more like this:
nums[0] = (static_cast<double>(sumCompletions) / sumAttempts - 0.3) * 5.0;
nums[1] = (static_cast<double>(sumYards) / sumAttempts - 3) * 0.25;
nums[2] = (static_cast<double>(sumTouchdowns) / sumAttempts) * 20.0;
nums[3] = 2.375 - (static_cast<double>(sumInterceptions) / sumAttempts) * 25.0;
By casting one of the terms in the divide to double, the division itself upgrades to double.
Alternately, you could just declare all of these variables to be double and avoid the casts entirely. That would make the code much easier to follow. Or, just make sumAttempts into a double, as it is common to all of the four divides.
I think the issue is in code like this:
static_cast<double>((sumCompletions / sumAttempts) - 0.3)
Here, sumCompletions and sumAttempts are ints. While you're trying to do a cast to a double to avoid integer division, the cast is on the complete value of the expression rather than on the numerator or denominator. This means that the division performed is integer division, which then has 0.3 subtracted and the result, which is already a double, is then cast to a double.
To fix this, cast the numerator or denominator, not the quotient itself:
static_cast<double>(sumCompletions) / sumAttempts - 0.3
Hope this helps!