Check precision to nth decimal place? - c++

I have to calculate the values of a hot plate and have it accurate only to the first decimal place. I am stumped on trying to figure out how to check all the array values if they changed. I found out that 724 runs made no change after that to the 4th decimal (how many were being printed).
Is there a way to compare doubles variables only up to the n-th decimal place?
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
const int ARRAY_SIZE = 20;
const int NEIGHBORS = 4;
void initialize(double hot_plate[][ARRAY_SIZE]);
bool writeFile(const double HOT_PLATE[][ARRAY_SIZE],
const string FILE_NAME);
double sum_cell(const double HOT_PLATE[][ARRAY_SIZE],
const int CELL_X, const int CELL_Y);
int main()
{
double hot_plate[ARRAY_SIZE][ARRAY_SIZE];
initialize(hot_plate);
string file_name = "hot_plate.csv";
//accuracy up to 4 decmials
int runs = 724;
while ( runs > 0)
{
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
if (i > 0 && i < ARRAY_SIZE - 1 && j > 0 && j < ARRAY_SIZE - 1)
{
hot_plate[i][j] = sum_cell(hot_plate, j, i);
}
}
}
runs--;
}
if (writeFile(hot_plate, file_name))
{
cout << "File wrote correctly\n";
}
else
{
cout << "The file did not write!\n";
}
//system("pause");
return 0;
}
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Completed Code ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
double sum_cell(const double HOT_PLATE[][ARRAY_SIZE],
const int CELL_X, const int CELL_Y)
{
/* This code should never go out of bounds as it's in an if statement
if (i > 0 && i < ARRAY_SIZE - 1 && j > 0 && j < ARRAY_SIZE - 1)
*/
double cell_num = HOT_PLATE[CELL_X - 1][CELL_Y]; // Top
cell_num += HOT_PLATE[CELL_X][CELL_Y - 1]; // Left
cell_num += HOT_PLATE[CELL_X][CELL_Y + 1]; // Right
cell_num += HOT_PLATE[CELL_X + 1][CELL_Y]; // Bottom
cell_num /= NEIGHBORS;
return cell_num;
}
// setup the Array so all values are defined when starting
void initialize(double hot_plate[][ARRAY_SIZE])
{
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
if (i == 0 || i == ARRAY_SIZE - 1)
{
if (j == 0 || j == ARRAY_SIZE - 1)
{
hot_plate[i][j] = 0.0;
}
else
{
hot_plate[i][j] = 100.0;
}
}
else
{
hot_plate[i][j] = 0.0;
}
}
}
}
// Write the data to the CSV file
bool writeFile(const double HOT_PLATE[][ARRAY_SIZE],
const string FILE_NAME)
{
// open the file
ofstream fout(FILE_NAME);
if (fout.fail())
return false;
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
fout << HOT_PLATE[i][j];
if ( j < ARRAY_SIZE - 1)
{
fout << ", ";
}
else if (i != ARRAY_SIZE - 1)
{
fout << endl;
}
}
}
// close the input stream from the file.
fout.close();
return true;
}

Is there a way to compare doubles variables only up to the n-th decimal place?
Yes there is, check whether the absolute value of the difference between them is less than 10^-n.

Check comparing floating point numbers and this post on deniweb.

With this function
double getUpToDecPlace (double value, int decPlace)
{
int dec = 1;
for (int i = 0; i < decPlace; i++)
{
dec *= 10;
}
return floor(value*dec + 0.5)/dec;
}
which would return 12.35 for getUpToDecPlace(12.345678, 2), you can compare doubles up to an arbitrary decimal place:
double var1 = 12.345678;
double var2 = 12.351234;
bool comp1 = (getUpToDecPlace(var1, 2) == getUpToDecPlace(var2, 2)); // true
bool comp2 = (getUpToDecPlace(var1, 3) == getUpToDecPlace(var2, 3)); // false

There are so many problems here.
You are updating the hot_plate array in-place. So some of the values you use from the 'previous generation' have already been updated in the current generation! You have to compute each generation in a separate array, and then copy it back to the 'master' hot_plate array.
If you want the final result accurate in the first decimal place, it's not enough to continue until the values don't change by more than 0.1. For instance, some values might change by more than 0.05 for ten more generations, which would amount to a change of more than 0.5. In fact, this is a very tricky issue: it requires a global analysis of how the initial conditions evolve over time.
Are you sure you have sum_cell right? The temperature of hot_plate[i][j] at the next generation should surely depend on the current value of hot_plate[i][j], and not just on its neighbours?
Also, this looks a bit silly:
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
if (i > 0 && i < ARRAY_SIZE - 1 && j > 0 && j < ARRAY_SIZE - 1)
I suggest the equivalent formulation:
for (int i = 1; i < ARRAY_SIZE - 1; i++)
{
for (int j = 1; j < ARRAY_SIZE - 1; j++)
As for testing equality to the nth decimal place, other posters have covered that.

Store the measured FP value as a scaled integer:
ix = int(fp * 10000)
You can then do direct comparisons with the required precision.

Related

Cannot get jacobi converted from gauss seidel in C++

I have coded up a gauss seidel method that works just fine but i cannot seem to figure out how to convert that to jacobi... I know it should be easy so i must be missing something simple. For the assignment i had to make my own vector and matrix classes so that is why Vector is capital and called differently. Here is my working gauss seidel code:
else if (mode == 3) {
Vector temp;
temp.allocateData(b.numElems());
Vector old = temp;
Vector sum;
double f = 50;
int y = 4;
double tol = 1e-12;
double error = 10;
int max = 999999;
int count = 0;
while ( error > tol && max > count) {
for (int i = 0; i < row_; i++) {
temp.setVal(i, b.getVal(i) / M[i][i]);
for (int j = 0; j < col_; j++) {
if (j == i) {
continue;
}
temp.setVal(i, temp.getVal(i) - ((M[i][j] / M[i][i]) * temp.getVal(j)));
old.setVal(j, temp.getVal(i));
}
cout<<"x"<< i + 1 << "="<< temp.getVal(i) <<" \n";
error = abs(temp.getVal(i)-old.getVal(i))/abs(temp.getVal(i));
old = temp;
}
cout << "\n";
count++;
}
}
and here is my attempt at jacobi:
else if (mode == 2) {
Vector temp;
temp.allocateData(b.numElems());
Vector old = temp;
Vector sum;
double f = 50;
int y = 4;
double tol = 1e-12;
double error = 10;
int max = 999999;
int count = 0;
while ( error > tol && max > count) {
old.allocateData(b.numElems());
for (int i = 0; i < row_; i++) {
old.setVal(i, temp.getVal(i));
temp.setVal(i, b.getVal(i) / M[i][i]);
for (int j = 0; j < col_; j++) {
if (j == i) {
continue;
}
temp.setVal(i, temp.getVal(i) - ((M[i][j] / M[i][i]) * old.getVal(j)));
}
cout<<"x"<< i + 1 << "="<< temp.getVal(i) <<" \n";
error = abs(temp.getVal(i)-old.getVal(i))/abs(temp.getVal(i));
}
cout << "\n";
count++;
}
}
thanks everyone ahead of time for the help!!!

Max value 2d array using pointer arithmetic

I'm trying to write a programm to find a maximum value in column in a initialized 5x5 matrix, and change it to -1. I found out the way to do it, but i want to find a better solution.
Input:
double array2d[5][5];
double *ptr;
ptr = array2d[0];
// initializing matrix
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
if (j % 2 != 0) {
array2d[i][j] = (i + 1) - 2.5;
} else {
array2d[i][j] = 2 * (i + 1) + 0.5;
}
}
}
This is my solution for the first column :
// Changing the matrix using pointer arithmetic
for (int i = 0; i < (sizeof(array2d) / sizeof(array2d[0][0])); ++i) {
if (i % 5 == 0) {
if (maxTemp <= *(ptr + i)) {
maxTemp = *(ptr + i);
}
}
}
for (int i = 0; i < (sizeof(array2d) / sizeof(array2d[0][0])); ++i) {
if (i % 5 == 0) {
if (*(ptr + i) == maxTemp) {
*(ptr + i) = -1;
}
}
}
I can repeat this code 5 times, and get the result, but i want a better solution. THX.
Below is the complete program that uses pointer arithmetic. This program replaces all the maximum values in each column of the 2D array -1 as you desire.
#include <iostream>
int main()
{
double array2d[5][5];
double *ptr;
ptr = array2d[0];
// initializing matrix
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
if (j % 2 != 0) {
array2d[i][j] = (i + 1) - 2.5;
} else {
array2d[i][j] = 2 * (i + 1) + 0.5;
}
}
}
//these(from this point on) are the things that i have added.
//Everything above this comment is the same as your code.
double (*rowBegin)[5] = std::begin(array2d);
double (*rowEnd)[5] = std::end(array2d);
while(rowBegin != rowEnd)
{
double *colBegin = std::begin(rowBegin[0]);
double *colEnd = std::end(rowBegin[0]);
double lowestvalue = *colBegin;//for comparing elements
//double *pointerToMaxValue = colBegin;
while(colBegin!= colEnd)
{
if(*colBegin > lowestvalue)
{
lowestvalue = *colBegin;
//pointerToMaxValue = colBegin ;
}
colBegin = colBegin + 1;
}
double *newcolBegin = std::begin(rowBegin[0]);
double *newcolEnd = std::end(rowBegin[0]);
while(newcolBegin!=newcolEnd)
{
if(*newcolBegin == lowestvalue)
{
*newcolBegin = -1;
}
++newcolBegin;
}
++rowBegin;
}
return 0;
}
The program can be checked here.
You can add print out all the element of the array to check whether the above program replaced all the maximum value in each column with -1.
I have written it in java but I think u can understand. This one is for all 5 columns at the same time. You can try this:
int count = 0;
double max = 0;
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
if (j == 0) {
max = array2d[j][I];
count = 0;
}
if (array2d[j][i] > max) {
count = j;
}
}
array2d[count][i] = -1;
}

Regular Matrix in C++

My homework will create a program that check the numbers in an array with a given pattern. Program must take the matrix dimensions and terms in the matrix as arguments from command line. For example program name is myProg.exe and we want to check a 2x3 dimensioned matrix with (maximum dimension limit is 20x20):
1 2 3
4 5 6
Then I will run your program as.
The program will check a special matrix pattern and prints out ACCEPTABLE or NOT MATCH according to the values we put from the console. The Special Pattern: In a row major representation the cells of the matrix must obey this rule. Some terms of the matrix must be sum or product of the neighbor cells. In row major representation the sum and product operations are placed as given in the examples. Sum and Product cells follows each other with one free cells. For Odd rows the sequence starts with free cells and in Even Rows the sequence starts with Sum or Product cell.
My code is here:
#include <iostream>
#include <sstream>
using namespace std;
static int iter = 0;
static unsigned int sat=3, sut=2;
bool ok = false;
int *accepted;
int *array;
string isAcceptable(int mat[]) {
int l, co = 0;
bool operation = false;
int mat2[sat][sut];
for (int i = 0; i < sat; i++) {
for (int j = 0; j < sut; j++) {
mat2[i][j] = mat[co];
co++;
}
}
for (int i = 0; i < sat; i++) {
if (i % 2 == 0)
l = 1;
else
l = 0;
for (int j = l; j < sut; j += 2) {
int totalProduct;
if (!operation) {
totalProduct = 0;
if (j > 0)
totalProduct += mat2[i][j - 1];
if (j < sut - 1)
totalProduct += mat2[i][j + 1];
if (i > 0)
totalProduct += mat2[i - 1][j];
if (i < sat - 1)
totalProduct += mat2[i + 1][j];
} else {
totalProduct = 1;
if (j > 0)
totalProduct *= mat2[i][j - 1];
if (j < sut - 1)
totalProduct *= mat2[i][j + 1];
if (i > 0)
totalProduct *= mat2[i - 1][j];
if (i < sat - 1)
totalProduct *= mat2[i + 1][j];
}
if (mat2[i][j] != totalProduct)
return "NOT MATCH";
operation = !operation;
}
}
return "ACCEPTABLE";
}
void change(int index1, int index2) {
int temp;
temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
iter++;
}
void combine(int mat[], int len) {
if(ok)
return;
array = new int[len];
*array = *mat;
if (len <= sat * sut) {
for (int i = len; i < sat * sut - 1; i++) {
for (int j = i; j < sat * sut; j++) {
combine(array, len + 1);
change(i, j);
if (isAcceptable(array) == ("ACCEPTABLE")) {
int accepted[sat*sut];
*accepted = *array;
ok = true;
return;
}
}
}
} else
return;
}
string isAcceptableCombine(int mat[]) {
combine(mat, 6);
if (ok)
{
cout<< " TRUE Sequense";
return "ACCEPTABLE";
}
else
cout<< " FALSE Sequense";
return "NOT MATCH";
}
int main(int argc, char** argv) {
int matris[] = {1,2,1,4,1,6};
isAcceptableCombine(matris);
}
My code's result is always returning TRUE Sequence.
Where is my mistake?

Sudoku solving matrix, while statement gives an infinite loop

This code should produce a solved sudoku matrix, however the while statement puts it in an infinite loop. Removing the while statement gives me a matrix with some values still 99 or 0. And i can't generate 9 random numbers uniquely one by one.
IF YOU WANT TO RUN AND CHECK THE CODE, REMOVE THE WHILE STATEMENT.
int a[9][9];
int b[9][9];
int inputvalue(int x, int y, int value) //checks horizontally, vertically and 3*3matrix for conflicts
{
int i, j;
for (i = 0; i < 9; i++)
{
if (value == a[x][i] || value == a[i][y])
return 0;
}
for (i = (x / 3) * 3; i <= ((x / 3) * 3) + 2; i++)
{
for (j = (y / 3) * 3; j <= ((y / 3) * 3) + 2; j++)
if (b[i][j] == value)
return 0;
}
return value;
}
int main()
{
int i, j, k;
unsigned int s;
cout << "sudoku\n";
time_t t;
s = (unsigned) time(&t);
srand(s);
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
a[i][j] = 99;
}
for (i = 0; i < 9; i++)
{
for (j = 1; j <= 9; j++)//j is basically the value being given to cells in the matrix while k assigns the column no.
while(a[i][k]==99||a[i][k]==0)
{
k = rand() % 9;
a[i][k] = inputvalue(i, k, j);
}
}
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
getch();
}
You are using assignment =, instead of equality == here:
while(a[i][k]=99||a[i][k]=0)
^ ^
this should be:
while(a[i][k]==99||a[i][k]==0)
a[i][k]=99 will always evaluate to true since 99 is non-zero, although your original code does not compile for me under gcc as it is, so I suspect the code you are running either has some parenthesizes or is slightly different.
Also using k in the while loop before it is initialized is undefined behavior and it is unclear that your termination logic makes sense for a k that is constantly changing for each loop iteration.
Another source of the infinite loop is inputvalue which seems to get stuck returning 0 in some instances, so you need to tweak that a bit to prevent infinite loops.
Also, srand(time(NULL)); is a more common way to initialize the pseudo-random number generator

C++ Loop Not Looping Appropriately

I have an array of 20 x 20 that outputs how hot a plate is. I need to reiterate through a loop until no cell in the array changes more than 0.1 degree(I refresh the values through every iteration. How would you monitor the largest change for any cell in an array in order to determine when to stop iterating? Right now I have tried, but the below doesn't output correctly.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
const int ARRAY_SIZE = 20;
const int NEIGHBORS = 4;
void initialize(double hot_plate[][ARRAY_SIZE]);
bool writeFile(const double HOT_PLATE[][ARRAY_SIZE],
const string FILE_NAME);
double sum_cell(const double HOT_PLATE[][ARRAY_SIZE],
const int CELL_X, const int CELL_Y);
int main()
{
double hot_plate[ARRAY_SIZE][ARRAY_SIZE];
double hot_plate_prev[ARRAY_SIZE][ARRAY_SIZE];
initialize(hot_plate);
string file_name = "hot_plate.csv";
//accuracy up to 4 decmials
int runs = 724;
double hot_plate[ARRAY_SIZE][ARRAY_SIZE];
double hot_plate_prev[ARRAY_SIZE][ARRAY_SIZE];
while (true)
{
// This is your code
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
if (i > 0 && i < ARRAY_SIZE - 1 && j > 0 && j < ARRAY_SIZE - 1)
{
hot_plate[i][j] = sum_cell(hot_plate, j, i);
}
}
}
bool theSame = true;
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
if (abs(hot_plate[i][j] - hot_plate_prev[i][j]) < 0.1)
{
theSame = false;
}
hot_plate_prev[i][j] = hot_plate[i][j];
}
}
if (!theSame) break;
}
}
if (writeFile(hot_plate, file_name))
{
cout << "File wrote correctly\n";
}
else
{
cout << "The file did not write!\n";
}
//system("pause");
return 0;
}
double sum_cell(const double HOT_PLATE[][ARRAY_SIZE],
const int CELL_X, const int CELL_Y)
{
/* This code should never go out of bounds as it's in an if statement
if (i > 0 && i < ARRAY_SIZE - 1 && j > 0 && j < ARRAY_SIZE - 1)
*/
double cell_num = HOT_PLATE[CELL_X - 1][CELL_Y]; // Top
cell_num += HOT_PLATE[CELL_X][CELL_Y - 1]; // Left
cell_num += HOT_PLATE[CELL_X][CELL_Y + 1]; // Right
cell_num += HOT_PLATE[CELL_X + 1][CELL_Y]; // Bottom
cell_num /= NEIGHBORS;
return cell_num;
}
// setup the Array so all values are defined when starting
void initialize(double hot_plate[][ARRAY_SIZE])
{
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
if (i == 0 || i == ARRAY_SIZE - 1)
{
if (j == 0 || j == ARRAY_SIZE - 1)
{
hot_plate[i][j] = 0.0;
}
else
{
hot_plate[i][j] = 100.0;
}
}
else
{
hot_plate[i][j] = 0.0;
}
}
}
}
// Write the data to the CSV file
bool writeFile(const double HOT_PLATE[][ARRAY_SIZE],
const string FILE_NAME)
{
// open the file
ofstream fout(FILE_NAME);
if (fout.fail())
return false;
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = 0; j < ARRAY_SIZE; j++)
{
fout << HOT_PLATE[i][j];
if ( j < ARRAY_SIZE - 1)
{
fout << ", ";
}
else if (i != ARRAY_SIZE - 1)
{
fout << endl;
}
}
}
// close the input stream from the file.
fout.close();
return true;
}
At the beginning of your while loop, you can set a boolean variable called something like allSmallChanges to true. In your inner if statement, you can check to see if the change to hot_plate[i][j] is "too big". If it is too big, then set allSmallChanges to false. Then, just before the end of the while loop, you can break if allSmallChanges is still true.
If you don't want to have that cap of 724 iterations, you can get rid of your runs variable, and change the loop to while(true).
Note: The code in the question got changed after I wrote this answer. I'm not sure this answer still applies. However, I'm also sure that will be the last change to the code in the question. So, I'll leave this answer as-is for now.