I am trying to create a program that prints the mapping data for found pythagorean triples in C. So far, I have coded the program to be able to find the triples.
#include <stdio.h>
#include <math.h>
int main (int argc, char * argv[]) {
int a, b, c;
int a2, b2, c2;
int limit = 60;
for (a = 1; a <= limit; a++) {
a2 = a * a;
for (b = 1; b <= limit; b++) {
b2 = b * b;
for (c = 0; c <= ((int)sqrt(a2+b2)); c++) {
c2 = c * c;
if (a < b && (c2 == (a2 + b2))) {
printf("triple: %d %d %d\n", a, b, c);
}
}
}
}
}
The intended output is expected in the format:
123456789012345678901234567890123456789012345678901234567890
1\
2 \
3 \
4 *\
5 \
6 \
7 \
8 * \
9 \
0 \
1 \
2 * * \
I am trying to write a loop that does this, but cannot think of how to print in this way. Any suggestions?
UPDATE: I managed to print the x and the y axis (x = a and y = b). The values are correct, now the mapping part is left.
for (int x = 0; x < a; x++) { // x-axis = a
printf("%d ", x);
}
printf("\n");
for (int y = 0; y < b; y++) { // y-axis = b
printf("%d\n", y);
}
UPDATE: Modified the code, the output is printing, but having problems printing spaces. tried manually adding spaces to the " \ " and " * " but that just distorts the whole image.
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
bool is_perfect_square(int num);
int main (int argc, char * argv[]) {
int a, b, c;
int a2, b2, c2;
int limit = 60;
bool flag = false;
for (a = 1; a <= limit; a++) {
a2 = a * a;
for (b = 1; b <= limit; b++) {
b2 = b * b;
for (c = 0; c <= ((int)sqrt(a2+b2)); c++) {
c2 = c * c;
if (a < b && (c2 == (a2 + b2))) {
// printf("triple: %d %d %d\n", a, b, c);
}
}
}
}
for (int x = 0; x < a; x++) {
for (int y = 0; y < b; y++) {
if (x == 0) {
printf("%d ", ((y+1)% 10));
} else if (y == 0) {
printf("%d ", (x % 10));
} else if (x == y) {
printf("\\");
} else if (is_perfect_square((x*x) + (y*y))) {
printf("*");
}
}
printf("\n");
}
}
bool is_perfect_square (int num) {
int root = (int)(sqrt(num));
if (num == root * root) {
return true;
} else {
return false;
}
}
Still working on possible solution.
Hint :
Have a nested loop with index i,j;
for i 0.. limit {
for j 0 .. limit {
/*Implement the below algorithm here!!*/
}
printf("\n")
}
Algorithm to be used inside the loop:
- if
i == 0
print x axis values by printing (j+1)% 10
[see note at end]
- else if
j == 0
print y axis values by printing i % 10
- else if
i == j
print '\'
- else if is_perfect_square(
(i*i) + (j*j)
) returns 1, print '*'
- else print a space.
Specifications for is_perfect_square function: A function that returns 1 if the input is a perfect square and 0 otherwise. For example:
is_perfect_square(25)
should return 1
is_perfect_square(7)
should return 0
is_perfect_square(49)
should return 1
Note: i == 0
case should print j%10
to start the output with 0 to represent origin. But the output provided in question starts with 1. Hence using (j+1)%10
You might need to handle some corner cases, which should be straight forward once this algorithm is implemented in code.
EASY WAY
If you manage to print all your stuff in the right order, you can easily avoid unnecessary if
statements and optimize the math calc as a side effect.
To find the Pythagorean triples I've modified your first method, so I can avoid the calls to sqrt
at every position.
#include <stdio.h>
#include <math.h>
// all the loops will test numbers from 1 to 60 included
#define LIMIT 61
int main ( int argc, char * argv[] ) {
int i, j, k, k2, sum;
// print the first line of reference numbers
// start with a space to allign the axes
putchar(' ');
// print every digit...
for ( i = 1; i < LIMIT; ++i )
putchar('0' + i%10);
// then newline
putchar('\n');
// now print every row
for ( i = 1; i < LIMIT; ++i ) {
// first print the number
putchar('0' + i%10);
// then test if the indeces (i,j) form a triple: i^2 + j^2 = k^2
// I don't want to call sqrt() every time, so I'll use another approach
k = i;
k2 = k * k;
for ( j = 1; j < i; ++j ) {
// this ^^^^^ condition let me find only unique triples and print
// only the bottom left part of the picture
// compilers should be (and they are) smart enough to optimize this
sum = i * i + j * j;
// find the next big enough k^2
if ( sum > k2 ) {
++k;
k2 = k * k;
}
// test if the triple i,j,k matches the Pythagorean equation
if ( sum == k2 )
// it's a match, so print a '*'
putchar('*');
else
// otherwise print a space
putchar(' ');
}
// the line is finished, print the diagonal (with a '\\') and newline
printf("\\\n");
// An alternative could be to put the reference numbers here instead:
// printf("%c\n",'0' + i%10);
}
return 0;
}
The output of this program is:
123456789012345678901234567890123456789012345678901234567890
1\
2 \
3 \
4 *\
5 \
6 \
7 \
8 * \
9 \
0 \
1 \
2 * * \
3 \
4 \
5 * \
6 * \
7 \
8 \
9 \
0 * \
1 *\
2 \
3 \
4 * * * \
5 \
6 \
7 \
8 * \
9 \
0 * \
1 \
2 * \
3 \
4 \
5 * \
6 * * \
7 \
8 \
9 \
0 * * \
1 \
2 * \
3 \
4 * \
5 * * \
6 \
7 \
8 * * * \
9 \
0 \
1 \
2 * \
3 \
4 \
5 * \
6 * * \
7 \
8 \
9 \
0 * * * * \
LESS EASY WAY
I'll show you another method to print out what you want.
Consider using an array of strings as a drawing space, stored in a struct.
It seems a complication, but you can simplify and maybe generalize the output procedures:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char **img;
int rows;
int cols;
} Image;
Image *init_image( int r, int c, char s ) {
int i;
char *tmp = NULL;
Image *pi = malloc(sizeof(Image));
if ( !pi ) {
perror("Error");
exit(-1);
}
pi->rows = r;
pi->cols = c;
pi->img = malloc(r * sizeof(char*));
if ( !pi->img ) {
perror("Error");
exit(-1);
}
for ( i = 0; i < r; ++i ) {
tmp = malloc(c + 1);
if ( !tmp ) {
perror("Error");
exit(-1);
}
// fill with initial value (spaces) and add the terminating NULL
memset(tmp,s,c);
tmp[c] = '\0';
pi->img[i] = tmp;
}
return pi;
}
void free_image( Image *pi ) {
int i;
if ( !pi || !pi->img ) return;
for ( i = 0; i < pi->rows; ++i ) {
free(pi->img[i]);
}
free(pi->img);
free(pi);
}
void draw_axes( Image *pi ) {
int i;
if ( !pi ) return;
// I use to loops because cols can be != rows, but if it's always a square...
for ( i = 1; i < pi->cols; ++i ) {
pi->img[0][i] = '0' + i%10;
}
for ( i = 1; i < pi->rows; ++i ) {
pi->img[i][0] = '0' + i%10;
}
}
void draw_diagonal ( Image *pi, char ch ) {
int i, m;
if ( !pi ) return;
m = pi->rows < pi->cols ? pi->rows : pi->cols;
for ( i = 1; i < m; ++i ) {
pi->img[i][i] = ch;
}
}
void print_image( Image *pi ) {
int i;
if ( !pi ) return;
for ( i = 0; i < pi->rows; ++i ) {
printf("%s\n",pi->img[i]);
}
}
void draw_triples( Image *pi, char ch ) {
int i, j, k, k2, sum;
for ( i = 1; i < pi->rows; ++i ) {
k = i;
k2 = k * k;
// print only the left bottom part
for ( j = 1; j < i && j < pi->cols; ++j ) {
sum = i * i + j * j;
if ( sum > k2 ) {
++k;
k2 = k * k;
}
if ( sum == k2 ) {
pi->img[i][j] = ch;
// printf("%d %d %d\n",i,j,k);
}
}
}
}
int main(int argc, char *argv[]) {
// Initialize the image buffer to contain 61 strings of 61 spaces
Image *img = init_image(61,61,' ');
// draw the reference numbers at row 0 and column 0
draw_axes(img);
// draw a diagonal with character '\'
draw_diagonal(img,'\\');
// put a '*' if a couple of coordinates forms a Pythagorean triple
draw_triples(img,'*');
// print out the image to stdout
print_image(img);
free_image(img);
return 0;
}
The output of this code is the same as the previous snippet, but, believe it or not, this is faster (at least on my system) due to the less numbers of function calls that print to stdout
.
ADDENDUM
It's way off topic, but I had fun adapting the previous code to actually output an image file (as a grayscaled 512x512 PGM binary formatted file) representing all the triples with side lengths up to 8192.
Every pixel correspond to a 16x16 square block, black colored if there is no match or lighter depending on how many triples the alghorithm found in the block.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *img; // store data in a 1D array this time
int dim;
int samples;
} Image;
Image *init_image( int d, int z );
void free_image( Image *pi );
void add_sample( Image *pi, int r, int c );
void draw_triples_sampled( Image *pi );
void save_image( char *file_name, Image *pi );
int main(int argc, char *argv[]) {
// store the results in a 512x512 image, with each pixel corresponding
// to a 16x16 square, so the test area is 8192x8192 wide
Image *img = init_image(512,16);
draw_triples_sampled(img);
save_image("triples.pgm",img);
free_image(img);
return 0;
}
Image *init_image( int d, int z ) {
Image *pi = malloc(sizeof(Image));
if ( !pi ) {
perror("Error");
exit(-1);
}
pi->dim = d;
pi->samples = z;
pi->img = calloc(d*d,1);
if ( !pi->img ) {
perror("Error");
exit(-1);
}
return pi;
}
void free_image( Image *pi ) {
if ( !pi ) free(pi->img);
free(pi);
}
void add_sample( Image *pi, int r, int c ) {
// each pixel represent a square block of samples
int i = r / pi->samples;
int j = c / pi->samples;
// convert 2D indeces to 1D array index
char *pix = pi->img + (i * pi->dim + j);
++(*pix);
}
void draw_triples_sampled( Image *pi ) {
int i, j, k, k2, sum;
int dim;
char *val;
if ( !pi ) return;
dim = pi->dim * pi->samples + 1;
for ( i = 1; i < dim; ++i ) {
k = i;
k2 = k * k;
// test only bottom left side for simmetry...
for ( j = 1; j < i; ++j ) {
sum = i * i + j * j;
if ( sum > k2 ) {
++k;
k2 = k * k;
}
if ( sum == k2 ) {
add_sample(pi,i-1,j-1);
// draw both points, thanks to simmetry
add_sample(pi,j-1,i-1);
}
}
}
}
void save_image( char *file_name, Image *pi ) {
FILE *pf = NULL;
char v;
char *i = NULL, *end = NULL;
if ( !pi ) {
printf("Error saving image, no image data\n");
return;
}
if ( !file_name ) {
printf("Error saving image, no file name specified\n");
return;
}
pf = fopen(file_name,"wb");
if ( !pf ) {
printf("Error saving image in file %s\n",file_name);
perror("");
return;
}
// save the image as a grayscale PGM format file
// black background, pixels from gray to white
fprintf(pf,"P5 %d %d %d ",pi->dim,pi->dim,255);
end = pi->img + pi->dim * pi->dim;
for ( i = pi->img; i != end; ++i ) {
if ( *i == 0 )
v = 0;
else if ( *i < 10 )
v = 105 + *i * 15;
else
v = 255;
fprintf(pf,"%c",v);
}
close(pf);
}
The output picture is (once converted to PNG to post here) this. Note the emerging patterns:
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
bool is_perfect_square(int num);
int main (int argc, char * argv[]) {
int a, b, c;
int a2, b2, c2;
int limit = 60;
bool flag = false;
for (a = 1; a <= limit; a++) {
a2 = a * a;
for (b = 1; b <= limit; b++) {
b2 = b * b;
for (c = 0; c <= ((int)sqrt(a2+b2)); c++) {
c2 = c * c;
if (a < b && (c2 == (a2 + b2))) {
// printf("triple: %d %d %d\n", a, b, c);
}
}
}
}
printf(" ");
for (int x = 0; x < a; x++) {
for (int y = 0; y < b; y++) {
if (x == 0) {
printf("%d", ((y+1) % 10));
} else if (y == 0) {
printf("%d", (x % 10));
} else if (x == y) {
printf("\\");
} else if (is_perfect_square((x*x) + (y*y))) {
printf("*");
} else {
printf(" ");
}
}
printf("\n");
}
}
bool is_perfect_square (int num) {
int root = (int)(sqrt(num));
if (num == root * root) {
return true;
} else {
return false;
}
}
FINAL UPDATE: finally managed to come up with this answer. a big thanks to Mr. Ravichandra. This is for anyone who might need something like this later. The code is not perfect and can be improved upon. The output is satisfactory and prints out a pattern almost similar to the desired output pattern.