在C中打印毕达哥拉斯三重奏的代表

我正在尝试创建一个程序,用于打印C中发现的毕达哥拉斯三元组的映射数据。到目前为止,我编写了程序以便能够找到三元组。

#include  #include  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); } } } } } 

预期输出的格式如下:

 123456789012345678901234567890123456789012345678901234567890 1\ 2 \ 3 \ 4 *\ 5 \ 6 \ 7 \ 8 * \ 9 \ 0 \ 1 \ 2 * * \ 

我正在尝试编写一个执行此操作的循环,但无法想到如何以这种方式进行打印。 有什么建议?

更新:我设法打印x和y轴(x = a和y = b)。 值是正确的,现在留下映射部分。

  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); } 

更新:修改了代码,输出正在打印,但是打印空间有问题。 尝试手动向“\”和“*”添加空格,但这只会扭曲整个图像。

 #include  #include  #include  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; } } 

仍在研究可能的解决方案。

提示:

有一个带索引i,j的嵌套循环;

 for i 0.. limit { for j 0 .. limit { /*Implement the below algorithm here!!*/ } printf("\n") } 

循环内使用的算法:

  • if i == 0通过打印(j+1)% 10打印x轴值[见末尾注]
  • 否则如果j == 0通过打印i % 10打印y轴值
  • 否则如果i == j打印'\'
  • 否则,如果is_perfect_square( (i*i) + (j*j) )返回1,则打印'*'
  • 否则打印一个空格。

is_perfect_square函数的规范:如果输入是完美的正方形则返回1的函数,否则返回0。 例如:

  • is_perfect_square(25)应该return 1
  • is_perfect_square(7)应该return 0
  • is_perfect_square(49)应该return 1

注意: i == 0 case应打印j%10以0开始输出以表示原点。 但是提供的输出从1开始。因此使用(j+1)%10

您可能需要处理一些极端情况,一旦在代码中实现此算法,这应该是直截了当的。

简单的方法

如果您设法以正确的顺序打印所有内容,则可以轻松避免不必要的if语句并优化数学计算作为副作用。

为了找到毕达哥拉斯三元组,我修改了你的第一个方法,所以我可以避免在每个位置调用sqrt

 #include  #include  // 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; } 

该程序的输出是:

  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 * * * * \ 

很简单的方式

我将向您展示另一种打印出您想要的方法。

考虑使用字符串数组作为绘图空间,存储在结构中。 这似乎是一个复杂的问题,但您可以简化并概括输出过程:

 #include  #include  #include  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; } 

此代码的输出与前一个代码段相同,但是,不管你信不信,这个更快(至少在我的系统上),因为打印到stdout的函数调用次数较少。

附录

这是偏离主题,但我很乐意调整以前的代码实际输出一个图像文件(作为灰度512×512 PGM二进制格式文件)代表所有三边形长度达8192的三元组。

每个像素对应一个16×16的方块,如果没有匹配则为黑色,或者根据块中的算法发现的三元组数量而变亮。

 #include  #include  #include  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); } 

输出图片(一旦转换为PNG以便在此发布)。 注意新兴的模式:

在此处输入图像描述

 #include  #include  #include  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; } } 

最终更新:终于设法得出这个答案。 非常感谢Ravichandra先生。 这适用于以后可能需要这样的人。 代码不完美,可以改进。 输出令人满意,并打印出与所需输出模式几乎相似的模式。