I've gotten stuck writing some parallel c code using OpenMP for a concurrency course.
Heres a snippet
#include <stdio.h>
#include <time.h>
#include <math.h>
#define FALSE 0
#define TRUE 1
int count_primes_0(int);
int count_primes_1(int);
int count_primes_2(int);
int main(int argc, char *argv[]){
int n;
if (argc != 2){
printf("Incorrect Invocation, use: \nq1 N");
return 0;
} else {
n = atoi(argv[1]);
}
if (n < 0){
printf("N cannot be negative");
return 0;
}
printf("N = %d\n", n);
//omp_set_num_threads(1);
time_it(count_primes_0, n, "Method 0");
time_it(count_primes_1, n, "Method 1");
time_it(count_primes_2, n, "Method 2");
return 0;
}
int is_prime(int n){
for(int i = 2; i <= (int)(sqrt((double) n)); i++){
if ((n % i) == 0){
return FALSE;
}
}
return n > 1;
}
void time_it( int (*f)(int), int n, char *string){
clock_t start_clock;
clock_t end_clock;
double calc_time;
int nprimes;
struct timeval start_val;
struct timeval end_val;
start_clock = clock();
nprimes = (*f)(n);
end_clock = clock();
calc_time = ((double)end_clock - (double)start_clock) / CLOCKS_PER_SEC;
printf("\tNumber of primes: %d \t Time taken: %fs\n\n", nprimes, calc_time);
}
// METHOD 0
// Base Case no parallelization
int count_primes_0(int n){
int nprimes = 0;
for(int i = 1; i <= n; i++){
if (is_prime(i)) {
nprimes++;
}
}
return nprimes;
}
//METHOD 1
// Use only For and Critical Constructs
int count_primes_1(int n){
int nprimes = 0;
#pragma omp parallel for
for(int i = 1; i <= n; i++){
if (is_prime(i)) {
#pragma omp critical
nprimes++;
}
}
return nprimes;
}
//METHOD 2
// Use Reduction
int count_primes_2(int n){
int nprimes = 0;
#pragma omp parallel for reduction(+:nprimes)
for(int i = 1; i <= n; i++){
if (is_prime(i)) {
nprimes++;
}
}
return nprimes;
}
The problem I'm facing is that when I use omp_set_num_threads() the less threads I use
the faster my functions run -- or get closer to the runtime of the base unparallelized case
Time Results:
These are run on an 8 core machine
8 Threads:
Method 0: 0.07s; Method 1: 1.63s; Method 2: 1.4s
4 Threads:
Method 0: 0.07s; Method 1: 0.16s; Method 2: 0.16s
2 Threads:
Method 0: 0.07s; Method 1: 0.10; Method 2: 0.09
1 Thread:
Method 0: 0.07s; Method 1: 0.08s; Method 2: 0.07s
I've tried disabling optimization and using a different gcc version with no difference
Any help is appreciated.
EDIT: Using clock in Linux returns the 'incorrect' time, wall clock time is what I needed so using ether omp_get_wtime() or the Linux function timeit would produce the proper results.
I am surprised that you have seen any success with the program as it is above. If you look at the RedHat Linux man page for clock(), you will see that it "returns an approximation of processor time used by the program". Putting in OpenMP directives causes more overhead, and thus you should see more overall processor time used when you run OpenMP. What you need to look at is elapse time (or wall clock time). When you run in parallel (and you have a program that can benefit from parallel), you will see the elapse time go down. The OpenMP specification defines a routine (omp_get_wtime()) to provide this information.
Changing your program to report using clock() and omp_get_wtime():
$ a.out 1000000 (1,000,000)
2 processors:
clock(): 0.23 wtime(): 0.23 clock(): 0.96 wtime(): 0.16 clock(): 0.59 wtime(): 0.09
4 processors:
clock(): 0.24 wtime(): 0.24 clock(): 0.97 wtime(): 0.16 clock(): 0.57 wtime(): 0.09
8 processors:
clock(): 0.24 wtime(): 0.24 clock(): 2.60 wtime(): 0.26 clock(): 0.64 wtime(): 0.09
$ a.out 10000000 (10,000,000)
2 processors:
clock(): 6.07 wtime(): 6.07 clock(): 10.4 wtime(): 1.78 clock(): 11.3 wtime(): 1.65
4 processors:
clock(): 6.07 wtime(): 6.07 clock(): 11.5 wtime(): 1.71 clock(): 10.7 wtime(): 1.72
8 processors:
clock(): 6.07 wtime(): 6.07 clock(): 9.92 wtime(): 1.83 clock(): 11.9 wtime(): 1.86
OpenMP does not parallelize loops with function calls inside it, unless arguments are private. A solution would be to inline is_prime() in your loop.
Related
Below I have a sample table stored in a text file - random.dat.
0.00 0.01 2.30 300
2.00 0.015 1.45 102
4.00 0.03 6.08 174
6.00 5.95 0.05 225
Now I want to read the contents of the table and store into an array. I have the following code that almost does the job.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int i,j;
int M = 3, N = 3;
FILE *fp;
double value1[M][N];
fp = fopen("random.dat","r");
if (fp == NULL)
{
exit(1);
}
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
fscanf(fp, "%lf", &value1[i][j]);
if (feof(fp))
{
break;
}
}
}
\*Just to check that my code has stored the arrays properly, I put the following printf statements*/
printf("%lf\n", value1[0][0]);
printf("%lf\n", value1[0][1]);
printf("%lf\n", value1[0][2]);
printf("%lf\n", value1[0][3]);
printf("%lf\n", value1[1][0]);
printf("%lf\n", value1[1][1]);
printf("%lf\n", value1[1][2]);
printf("%lf\n", value1[1][3]);
}
The values that I want and thought the program would give me:
value1[0][0] = 0.00 value1[0][1] = 0.01 value1[0][2] = 2.30 value1[0][3] = 300
value1[1][0] = 2.00 value1[1][1] = 0.015 value1[1][2] = 1.45 value1[1][3] = 102
Instead, it gives me,
value1[0][0] = 0.00 value1[0][1] = 0.01 value1[0][2] = 2.30 value1[0][3] = 300.0
value1[1][0] = 300.0 value1[1][1] = 2.00 value1[1][2] = 0.015 value1[1][3] = 1.45
I couldn't figure out a solution for this. Can someone point where I have made an error?
Thank you
If M and N are 3, value1 [0] [3] is out of bounds. Change N to 4.
I wrote a C program to find out the prime numbers in a given parameter. But for the same input and output, the program has different execution times.
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n,p,k;
scanf("%d", &n);
int prime[n+1];
for (p = 2; p <= n; ++p)
{
if (prime[p]!=-1)
{
for (int i = p*2,k=2; i < n; k++,i=k*p)
{
prime[i]=-1;
}
}
}
for (int i = 1; i < n ; ++i)
{
if (prime[i]!=-1)
{
printf("%d ",i );
}
}
return 0;
}
What you are measuring is the time it takes the user to type the input, i.e. 200.
Calculating the result after the input is given will not take 2 to 5 sec on any modern computer.
It is true that "the computer may be doing other things" and therefore give varying execution time - but that won't give you a 3 sec increase in code like this.
To make the measurement more reliable, you need to "remove" the user input, i.e. remove the scanf.
Instead of scanf you should give the value of n as a command line argument.
Use code like
// scanf("%d", &n); Dont use scanf but use lines like the two below.
if (argc < 2) exit(1); // user error - no number given
n = atoi(argv[1]); // convert command line arg to integer
And start the program like:
test2.exe 200
Now the measured time will be much smaller than 2-5 sec and you won't see execution time vary so much.
Note: While atoi is simple to use, it's in general better to use strtol
The execution of a program on an environment is not dependent only on the code but on some other environment variables such as CPU load.
CLOCKS_PER_SEC is a constant which is declared in <time.h>. To get the CPU time used by a task within a C application, use:
clock_t begin = clock();
/* Do the work. */
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
For your program, You can probably check the
CPU Time took on input.
CPU Time is taken to generate Prime Number
...... and so on
#include <stdio.h>
#include<time.h>
int main(int argc, char const *argv[])
{
int n,p,k;
clock_t t , t1, t2;
t = clock();
scanf("%d", &n);
t = clock() - t;
double time_taken = ((double)t)/CLOCKS_PER_SEC; // in seconds
printf("Took %f seconds to take the input\n", time_taken);
t2 = clock();
int prime[n+1];
for (p = 2; p <= n; ++p)
{
if (prime[p]!=-1)
{
for (int i = p*2,k=2; i < n; k++,i=k*p)
{
prime[i]=-1;
}
}
}
t2 = clock() - t2;
double time_taken2 = ((double)t2)/CLOCKS_PER_SEC; // in seconds
printf("Took %f seconds for generating the prime number \n", time_taken2);
for (int i = 1; i < n ; ++i)
{
if (prime[i]!=-1)
{
printf("%d ",i );
}
}
return 0;
}
Output:
200
Took 0.000075 seconds to take the input
Took 0.000004 seconds for generating the prime number
1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 1
13 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
The time is depended on your CPU load. For details please visit here
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#define len 10
#define hi 10
void transpose(double (*matrix)[len][hi]);
int main() {
srand(time(NULL));
double (*matrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
double delimo, delitel;
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
delimo = rand()%(len * hi);
delitel = rand()%(len * hi);
*matrix[i][j] = delimo/++delitel;
printf(" %5.2lf ", *matrix[i][j]);
}
puts("");
}
puts("Transpose: ");
transpose(matrix);
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
printf(" %5.2lf ", *matrix[i][j]);
}
puts("");
}
free(matrix);
}
void transpose(double (*matrix)[len][hi]){
double (*Tmatrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
*Tmatrix[i][j] = *matrix[j][i];
}
}
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
*matrix[i][j] = *Tmatrix[i][j];
}
}
free(Tmatrix);
}
Task is to allocate a 2d array and then have a function transpose it and copy the transposed matrix in the original one with one function call. The dimensions of the matrix are set by the macros and they are also used in a few loops and when allocating the 2 matrixes. Yet for some odd reason, there's a segfault if I decide to change them. Only thing that has never crashed is when len = hi = 10 . In any other case the program has an average to above average chance to crash.
The code shown in the question gives my build of Valgrind conniptions because it is not using the pointer-to-matrix notation correctly. When run standalone (not under Valgrind) it appears to work, but the output matrix is not a transpose of the input matrix — because the data has not been accessed correctly. This is an example of the bogus output I get. You can see that the elements with indices 0,1 and 1,0 in the 'transpose' matrix are unrelated to the elements in the original matrix.
1.24 2.64 0.17 0.49 22.25 4.30 0.71 1.12 1.03 2.31
1.39 7.18 0.40 0.44 4.30 0.17 0.62 12.67 0.34 9.10
2.85 0.69 3.50 1.58 0.77 0.04 0.26 0.79 0.24 1.59
16.00 0.14 0.12 0.56 1.68 0.08 0.69 0.13 2.51 1.74
5.50 0.96 0.45 1.00 0.00 0.84 0.97 0.40 2.14 0.67
2.00 0.14 1.84 0.88 1.26 0.21 0.70 0.30 1.74 0.60
2.04 1.00 0.35 0.12 0.00 0.65 1.21 0.18 0.52 9.70
1.19 1.08 0.88 1.71 0.88 0.21 1.74 0.70 0.44 1.23
1.38 0.69 0.12 0.14 4.18 3.17 0.06 7.10 8.00 1.52
0.16 6.07 0.81 0.49 0.14 1.37 4.00 0.93 0.98 1.48
Transpose:
1.24 1.24 2.64 0.17 0.49 22.25 4.30 0.71 1.12 1.03
-2.00 1.39 1.39 2.85 16.00 5.50 2.00 2.04 1.19 1.38
0.17 2.85 0.69 0.69 0.14 0.96 0.14 1.00 1.08 0.69
0.49 16.00 0.14 0.12 0.12 0.45 1.84 0.35 0.88 0.12
22.25 5.50 0.96 0.45 1.00 1.00 0.88 0.12 1.71 0.14
4.30 2.00 0.14 1.84 0.88 1.26 1.26 0.00 0.88 4.18
0.71 2.04 1.00 0.35 0.12 0.00 0.65 0.65 0.21 3.17
1.12 1.19 1.08 0.88 1.71 0.88 0.21 1.74 1.74 0.06
1.03 1.38 0.69 0.12 0.14 4.18 3.17 0.06 7.10 7.10
2.31 0.16 6.07 0.81 0.49 0.14 1.37 4.00 0.93 0.98
The code below works for square matrices. The difference is that the pointer-to-matrix is dereferenced before the subscripting is applied ((*matrix)[i][j]) instead of after (*matrix[i][j]).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define len 10
#define hi 10
void transpose(double (*matrix)[len][hi]);
int main(void)
{
srand(time(NULL));
double (*matrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
double delimo, delitel;
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
delimo = rand() % (len * hi);
delitel = rand() % (len * hi);
(*matrix)[i][j] = delimo / ++delitel;
printf(" %5.2lf ", (*matrix)[i][j]);
}
puts("");
}
puts("Transpose: ");
transpose(matrix);
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
printf(" %5.2lf ", (*matrix)[i][j]);
}
puts("");
}
free(matrix);
}
void transpose(double (*matrix)[len][hi])
{
double (*Tmatrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
(*Tmatrix)[i][j] = (*matrix)[j][i];
}
}
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
(*matrix)[i][j] = (*Tmatrix)[i][j];
}
}
free(Tmatrix);
}
Example output:
0.98 0.90 0.16 0.08 0.48 1.71 0.53 0.24 2.28 1.79
0.73 0.36 2.00 3.27 0.29 1.25 19.40 1.60 0.56 0.00
3.00 10.50 1.81 1.56 1.11 0.78 1.53 0.71 1.27 0.93
2.10 0.56 2.34 1.48 0.81 2.16 0.47 0.16 7.62 0.91
0.93 2.48 0.15 0.71 1.09 0.73 0.58 0.48 1.13 0.99
0.59 0.72 8.75 2.19 61.00 1.41 2.08 0.83 0.65 0.16
0.42 1.13 0.85 1.00 3.00 0.55 0.33 1.67 0.44 0.69
0.08 1.17 0.25 0.92 1.04 0.17 1.77 1.95 0.50 0.90
2.28 0.35 0.41 1.27 0.80 3.36 0.29 0.13 3.88 0.39
0.64 0.50 0.40 0.15 0.45 0.78 0.31 1.48 1.50 1.06
Transpose:
0.98 0.73 3.00 2.10 0.93 0.59 0.42 0.08 2.28 0.64
0.90 0.36 10.50 0.56 2.48 0.72 1.13 1.17 0.35 0.50
0.16 2.00 1.81 2.34 0.15 8.75 0.85 0.25 0.41 0.40
0.08 3.27 1.56 1.48 0.71 2.19 1.00 0.92 1.27 0.15
0.48 0.29 1.11 0.81 1.09 61.00 3.00 1.04 0.80 0.45
1.71 1.25 0.78 2.16 0.73 1.41 0.55 0.17 3.36 0.78
0.53 19.40 1.53 0.47 0.58 2.08 0.33 1.77 0.29 0.31
0.24 1.60 0.71 0.16 0.48 0.83 1.67 1.95 0.13 1.48
2.28 0.56 1.27 7.62 1.13 0.65 0.44 0.50 3.88 1.50
1.79 0.00 0.93 0.91 0.99 0.16 0.69 0.90 0.39 1.06
You can't transpose a non-square matrix in situ. If you have an nxm matrix as input, the transpose is an mxn matrix. It is probably simplest to allocate the transpose matrix where you allocate the non-transpose, and pass both matrices to the transpose function. Note the use of *matrix to pass the pointer-to-matrix as a matrix to the function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void transpose(int rows, int cols, double matrix[rows][cols], double result[cols][rows]);
void print_matrix(const char *tag, int rows, int cols, double matrix[rows][cols]);
int main(void)
{
srand(time(NULL));
int cols = 10;
int rows = 8;
double (*matrix)[rows][cols] = malloc(sizeof(double[rows][cols]));
double (*result)[cols][rows] = malloc(sizeof(double[cols][rows]));
if (matrix == 0 || result == 0)
{
fprintf(stderr, "failed to allocate memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
double delimo = rand() % (rows * cols);
double delitel = rand() % (rows * cols) + 1;
(*matrix)[i][j] = delimo / delitel;
}
}
print_matrix("original", rows, cols, *matrix);
transpose(rows, cols, *matrix, *result);
print_matrix("transpose", cols, rows, *result);
free(matrix);
free(result);
return 0;
}
void print_matrix(const char *tag, int rows, int cols, double matrix[rows][cols])
{
printf("%s (%dx%d):\n", tag, rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf(" %5.2f ", matrix[i][j]);
putchar('\n');
}
}
void transpose(int rows, int cols, double matrix[rows][cols], double result[cols][rows])
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
result[j][i] = matrix[i][j];
}
}
}
Sample output:
original (8x10):
0.84 0.92 0.18 1.97 4.54 31.00 1.59 0.11 0.35 0.07
0.96 3.19 1.00 4.86 3.25 3.50 2.65 1.07 0.24 0.77
6.00 0.13 0.40 1.04 0.99 0.88 1.24 0.67 3.07 12.00
1.89 0.48 0.72 0.55 0.26 0.64 0.55 0.09 0.30 0.98
0.51 0.86 0.85 0.33 1.44 0.89 2.38 2.21 0.27 2.12
6.40 1.71 2.83 1.61 0.76 0.13 0.81 1.48 1.13 0.51
0.79 0.69 0.57 1.10 1.00 1.31 0.68 1.95 1.42 0.46
0.00 0.43 1.64 0.88 1.03 0.14 0.35 1.78 0.86 2.82
transpose (10x8):
0.84 0.96 6.00 1.89 0.51 6.40 0.79 0.00
0.92 3.19 0.13 0.48 0.86 1.71 0.69 0.43
0.18 1.00 0.40 0.72 0.85 2.83 0.57 1.64
1.97 4.86 1.04 0.55 0.33 1.61 1.10 0.88
4.54 3.25 0.99 0.26 1.44 0.76 1.00 1.03
31.00 3.50 0.88 0.64 0.89 0.13 1.31 0.14
1.59 2.65 1.24 0.55 2.38 0.81 0.68 0.35
0.11 1.07 0.67 0.09 2.21 1.48 1.95 1.78
0.35 0.24 3.07 0.30 0.27 1.13 1.42 0.86
0.07 0.77 12.00 0.98 2.12 0.51 0.46 2.82
Valgrind gives both of these a clean bill of health. The original code caused Valgrind to report a lot of errors like:
==33404== Signal 11 being dropped from thread 0's queue
I had to kill that run from a different terminal window.
You are trying to transpose a matrix in place, which is problematic. Indeed, transposing a non-square matrix gives a matrix of different dimension. Therefore you will inadvertently write to memory you are not supposed to access, because you try to fit your transposed matrix in an array of incorrect dimension.
I suggest you to modify your transpose function such that it takes two matrices as arguments. The first is your matrix to transpose, the second is the one receiving the transposed matrix and it has the correct dimension.
You are trying too hard. Simply remove all the dynamic allocation stuff as well as pointers. Dynamic memory allocation is totally useless in your case.
Here you go:
#define len 2
#define hi 2
void transpose(double matrix[len][hi]);
int main() {
srand(time(NULL));
double matrix[len][hi];
double delimo, delitel;
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
delimo = rand() % (len * hi);
delitel = rand() % (len * hi);
matrix[i][j] = delimo / ++delitel;
printf(" %5.2lf ", matrix[i][j]);
}
puts("");
}
puts("Transpose: ");
transpose(matrix);
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
printf(" %5.2lf ", matrix[i][j]);
}
puts("");
}
}
void transpose (double matrix[len][hi]) {
double Tmatrix[len][hi];
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
Tmatrix[i][j] = matrix[j][i];
}
}
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
matrix[i][j] = Tmatrix[i][j];
}
}
}
Disclaimer:
this only works for square matrixes.
there may be other problems
edit: Apparently the variabledmaxdoesn't update with every loop.
I have 2 files that are scanned and inputted into 2 separate arrays but when I run the code to find the daily maximum difference between the same elements of the 2 arrays, the output reaches 107374208.000000. Here is my code down below.
void diff()
{
float ftemp[size], mtemp[size], diff[size], count = 1.0;
feb = fopen("feb.txt", "r");
mar = fopen("mar.txt", "r");
for(i = 1; i < size; i++)
{
fscanf(feb, "%f", &ftemp[i]);
fscanf(mar, "%f", &mtemp[i]);
dmax = (i * 3) - 3;
if((mtemp[dmax] - ftemp[dmax]) > count && (mtemp[dmax] - ftemp[dmax]) > 0)
{
count = mtemp[dmax] - ftemp[dmax];
}
}
printf("The highest temperature difference between March and February is %f.\n", count);
}
this is the daily temperatures for February
maximum minimum average
31.6 22.4 25.9
30.2 22.7 25.5
31.2 22.9 26.1
31.3 23.4 26.4
30.7 23.2 26.2
31.3 23.1 26.4
31.6 23.9 26.4
31.6 24.0 26.9
32.7 24.7 27.5
33.8 24.8 27.7
32.4 25.0 27.6
32.1 24.9 27.6
32.7 25.4 27.9
31.9 25.5 27.6
31.9 25.4 27.8
32.1 25.3 27.8
31.7 25.6 27.8
32.6 25.2 27.7
32.2 24.9 27.5
32.2 24.9 27.7
31.7 25.8 27.7
32.3 25.5 27.9
32.1 24.4 27.3
31.5 24.6 27.2
31.8 24.0 27.0
32.0 24.4 27.4
32.4 24.9 27.8
32.1 25.0 27.6
and this is the daily temperatures of March
maximum minimum average
32.7 25.1 27.7
33.8 24.8 28.0
32.9 24.7 27.6
32.9 25.0 27.8
32.9 25.0 27.8
33.0 23.8 27.5
32.6 24.2 27.6
32.8 24.8 27.9
32.0 24.2 27.6
32.3 24.9 27.8
33.6 25.0 28.1
33.4 25.6 28.3
33.8 24.7 28.3
34.1 25.2 28.6
32.7 25.9 28.6
28.2 23.6 25.9
30.7 24.3 26.4
32.7 24.9 27.5
32.5 25.4 27.5
33.6 25.9 27.6
33.1 25.3 27.7
31.0 25.0 27.5
32.8 24.2 27.9
33.0 24.7 28.1
33.2 25.2 28.4
34.0 25.7 28.8
34.4 25.8 29.1
32.7 26.2 28.6
33.3 26.5 28.5
32.3 25.8 28.5
33.0 26.6 28.8
The code doesn't compile because there's a bunch of undeclared variables like dmax and ftemp.
After fixing that...
The fopens are unchecked.
The files are assumed to be a certain size.
It's reading well past the initialized portion of the arrays.
fscanf is not checked.
fscanf is a bug generator.
Let's have a look at your loop.
for(i = 1; i < size; i++)
{
fscanf(feb, "%f", &ftemp[i]);
fscanf(mar, "%f", &mtemp[i]);
dmax = (i * 3) - 3;
if((mtemp[dmax] - ftemp[dmax]) > count && (mtemp[dmax] - ftemp[dmax]) > 0)
{
count = mtemp[dmax] - ftemp[dmax];
}
}
After the first iteration, dmax will always be larger than i (i = 0, dmax = 0; i = 1, dmax = 3; i = 2, dmax = 6). But the loop is only ever populated up to i. So mtemp[dmax] and ftemp[dmax] will never be populated when you try to use them. You'll get garbage.
I suspect you're assuming that fscanf(feb, "%f", &ftemp[i]) is scanning in a whole row of numbers. It's only scanning in one, just like you asked for. To do a whole row, you have to ask for that.
for( int i = 0; i < size; i += 3 ) {
fscanf(feb, "%f %f %f", &ftemp[i], &ftemp[i+1], &ftemp[i+2]);
fscanf(mar, "%f %f %f", &mtemp[i], &mtemp[i+1], &mtemp[i+2]);
...
}
Note that the loop starts at 0 because arrays start from 0. And it advances by 3, because we're reading in 3 at a time.
This still doesn't work. The first line of your files are all strings, not floating point numbers. fscanf doesn't skip ahead to find a match, if it doesn't match it stops. If you keep trying the same match it will keep trying to read from the same position over and over and over and over again. All your code is doing is trying to read in the first bytes of each file as a floating point number, failing, and then doing it again size times. ftemp[i] and mtemp[i] remain uninitialized so you get garbage.
This is why scanf and fscanf should be avoided. Instead, read in whole lines and process them with sscanf.
The arrays are also unnecessary, you're not doing anything with the previous values, you just need the current min and max.
Taking that all into account, and a few other things, I've rewritten it like this:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
/* A little function to open files while checking it was
successful and giving a good error message if not */
FILE *open_file( const char *file, const char *mode ) {
FILE *fp = fopen(file, mode);
if( fp == NULL ) {
fprintf(
stderr,
"Could not open '%s' for '%s': %s\n",
file, mode, strerror(errno)
);
exit(1);
}
return fp;
}
/* Instead of using hard coded file names, they're passed in. */
/* Instead of hard coding the use of the diff, it's returned. */
/* I switched to doubles because that's what fabs() returns and
the extra accuracy can't hurt. */
double largest_max_temp_diff(const char *file1, const char* file2) {
FILE *feb = open_file(file1, "r");
FILE *mar = open_file(file2, "r");
char line1[1024];
char line2[1024];
/* Skip the header lines */
fgets(line1, 1024, feb);
fgets(line2, 1024, mar);
double max_diff = 0;
/* Loop infinitely, loop exit is handled using `break` */
while(1) {
/* Read in a line from each file.
Stop when we reach the end of either file. */
if( fgets(line1, 1024, feb) == NULL ) {
break;
}
if( fgets(line2, 1024, mar) == NULL ) {
break;
}
/* Read in just the first column, ignore the rest. */
/* Make sure the parsing was successful. */
double max1, max2;
if( sscanf(line1, "%lf %*lf %*lf", &max1) < 1 ) {
fprintf( stderr, "Could not understand '%s'", line1);
continue;
}
if( sscanf(line2, "%lf %*lf %*lf", &max2) < 1 ) {
fprintf( stderr, "Could not understand '%s'", line2);
continue;
}
/* Compare the diffs as absolute values */
double diff = max2 - max1;
if(fabs(diff) > fabs(max_diff)) {
max_diff = diff;
}
}
/* Return the max diff so it can be used as the caller likes */
return max_diff;
}
int main() {
/* Get the diff */
double diff = largest_max_temp_diff("feb.txt", "mar.txt");
/* Use it */
printf("The highest temperature difference between March and February is %f.\n", diff);
}
This new code now skips the header lines. It reads a line and parses it separately guaranteeing it won't get stuck. It parses one line at a time using sscanf only storing the max. It checks that the parsing succeeded.
It uses the absolute value to check for the maximum difference, because a difference of -4 is bigger than 3.
Finally, it returns that value for the caller to do what it wants with it. Calculating and printing (or any formatting) in the same function is a red flag; it makes functions inflexible and you wind up writing a lot of duplicate code.
It's not the best code, there's still a lot of duplication, but it's better and it checks itself. When working with files, you always have to check your assumptions.
I am trying to load a 3x8 array of doubles but my code keeps outputting 0.00 for all of the values. The code should be outputting the array (same as the input) under the Read#1 Read#2 Read#3 lines, with the average under average.
Here is my code:
#include <stdio.h>
double getAvg(double num1, double num2, double num3);
int main()
{
int numJ,month,day,year,i,j;
double arr[3][8];
scanf("%d %d %d %d",&numJ,&month,&day,&year);
for (i = 0; i < 8; i++)
{
scanf("%f %f %f",&arr[i][0], &arr[i][1], &arr[i][2]);
}
printf("\nJob %d Date: %d/%d/%d",numJ,month,day,year);
printf("\n\nLocation Read#1 Read#2 Read#3 Average");
for (j = 0; j < 8; j++)
{
printf("\n %d %.2f %.2f %.2f %.2f",j+1,arr[j][0],arr[j] [1],arr[j][2],getAvg(arr[j][0],arr[j][1],arr[j][2]));
}
return 0;
}
double getAvg(double num1, double num2, double num3)
{
double avg = (num1 + num2 + num3) / 3;
return avg;
}
Input example:
157932 09 01 2013
0.00 0.00 0.00
0.36 0.27 0.23
0.18 0.16 0.26
0.27 0.00 0.34
0.24 0.00 0.31
0.16 0.33 0.36
0.29 0.36 0.00
0.21 0.36 0.00