mirror of
https://github.com/mfillpot/mathomatic.git
synced 2026-01-09 04:59:37 +00:00
228 lines
4.9 KiB
C
228 lines
4.9 KiB
C
/*
|
|
* Calculate and display Pascal's triangle.
|
|
*
|
|
* Copyright (C) 2005 George Gesslein II.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
The chief copyright holder can be contacted at gesslein@mathomatic.org, or
|
|
George Gesslein II, P.O. Box 224, Lansing, NY 14882-0224 USA.
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
#include <assert.h>
|
|
#if !MINGW
|
|
#include <sys/ioctl.h>
|
|
#include <termios.h>
|
|
#endif
|
|
|
|
#define true 1
|
|
#define false 0
|
|
|
|
#ifndef LDBL_DIG
|
|
#define USE_DOUBLES 1
|
|
#warning "long doubles not supported by this C compiler."
|
|
#endif
|
|
|
|
#if USE_DOUBLES
|
|
typedef double double_type;
|
|
#warning "Using only double floats instead of long double floats, as requested."
|
|
#else
|
|
typedef long double double_type;
|
|
#endif
|
|
|
|
#define MAX_LINES 1000 /* max number of lines of Pascal's triangle allowed */
|
|
|
|
void allocate_triangle(void);
|
|
void calculate_triangle(void);
|
|
void display_triangle(void);
|
|
int center_buf(int line_no, int cell_size);
|
|
void usage(int ev);
|
|
|
|
#if USE_DOUBLES
|
|
int precision = DBL_DIG;
|
|
#else
|
|
int precision = LDBL_DIG;
|
|
#endif
|
|
int glines = 26;
|
|
int gcell_size = 6;
|
|
double_type *garray[MAX_LINES];
|
|
int screen_columns = 80;
|
|
int centered = true;
|
|
char gline_buf[1000];
|
|
|
|
char *prog_name = "matho-pascal";
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
#if !MINGW
|
|
struct winsize ws;
|
|
|
|
ws.ws_col = 0;
|
|
ws.ws_row = 0;
|
|
ioctl(1, TIOCGWINSZ, &ws);
|
|
if (ws.ws_col > 0) {
|
|
screen_columns = ws.ws_col;
|
|
}
|
|
#endif
|
|
if (screen_columns >= sizeof(gline_buf)) {
|
|
screen_columns = sizeof(gline_buf) - 1;
|
|
}
|
|
|
|
switch (argc) {
|
|
case 0:
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
centered = false;
|
|
if (isdigit(argv[1][0])) {
|
|
glines = atoi(argv[1]);
|
|
break;
|
|
}
|
|
default:
|
|
usage(EXIT_FAILURE);
|
|
}
|
|
if (glines <= 0 || glines > MAX_LINES) {
|
|
fprintf(stderr, "%s: Number of lines out of range (1..%d).\n", prog_name, MAX_LINES);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
allocate_triangle();
|
|
calculate_triangle();
|
|
display_triangle();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
void
|
|
allocate_triangle(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < glines; i++) {
|
|
garray[i] = (double_type *) calloc(i + 1, sizeof(double_type));
|
|
if (garray[i] == NULL) {
|
|
fprintf(stderr, "%s: Not enough memory.\n", prog_name);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
calculate_triangle(void)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < glines; i++) {
|
|
for (j = 0; j <= i; j++) {
|
|
if (j == 0 || j == i) {
|
|
garray[i][j] = 1.0; /* the line begins and ends with 1 */
|
|
} else {
|
|
garray[i][j] = garray[i-1][j-1] + garray[i-1][j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
display_triangle(void)
|
|
{
|
|
int i, j;
|
|
int len;
|
|
|
|
if (centered && glines > 20) {
|
|
len = center_buf(19, 8);
|
|
if (len > 0 && len < screen_columns) {
|
|
gcell_size = 8; /* for very wide screens */
|
|
}
|
|
}
|
|
for (i = 0; i < glines; i++) {
|
|
if (centered) {
|
|
len = center_buf(i, gcell_size);
|
|
if (len <= 0 || len >= screen_columns) {
|
|
return; /* stop here because of wrap-around */
|
|
}
|
|
/* center on screen */
|
|
for (j = (screen_columns - len) / 2; j > 0; j--) {
|
|
printf(" ");
|
|
}
|
|
printf("%s", gline_buf);
|
|
} else {
|
|
for (j = 0; j <= i; j++) {
|
|
#if USE_DOUBLES
|
|
printf("%.*g ", precision, garray[i][j]);
|
|
#else
|
|
printf("%.*Lg ", precision, garray[i][j]);
|
|
#endif
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Create a line of output in gline_buf[] for centering mode.
|
|
|
|
* Return length if successful, otherwise return 0.
|
|
*/
|
|
int
|
|
center_buf(int line_no, int cell_size)
|
|
{
|
|
int j, k;
|
|
int i1;
|
|
int len;
|
|
char buf2[100];
|
|
|
|
assert(line_no < glines);
|
|
gline_buf[0] = '\0';
|
|
for (j = 0; j <= line_no; j++) {
|
|
#if USE_DOUBLES
|
|
len = snprintf(buf2, sizeof(buf2), "%.*g", precision, garray[line_no][j]);
|
|
#else
|
|
len = snprintf(buf2, sizeof(buf2), "%.*Lg", precision, garray[line_no][j]);
|
|
#endif
|
|
assert(len > 0);
|
|
if (len >= cell_size) {
|
|
return(0); /* cell_size too small */
|
|
}
|
|
/* center in the cell */
|
|
for (k = i1 = (cell_size - len) / 2; k > 0; k--) {
|
|
strcat(gline_buf, " ");
|
|
}
|
|
strcat(gline_buf, buf2);
|
|
for (k = len + i1; k < cell_size; k++) {
|
|
strcat(gline_buf, " ");
|
|
}
|
|
}
|
|
return(strlen(gline_buf));
|
|
}
|
|
|
|
void
|
|
usage(int ev)
|
|
{
|
|
printf("Usage: %s [number-of-lines]\n\n", prog_name);
|
|
printf("Display up to %d lines of Pascal's triangle.\n", MAX_LINES);
|
|
printf("If number-of-lines is specified, don't center output.\n");
|
|
printf("Number of digits of precision is %d.\n", precision);
|
|
exit(ev);
|
|
}
|