C从命令行读入数学方程式

时间:2016-11-19 13:39:16

标签: c function input equation

目前,我正在编写一个程序,通过使用梯形规则计算方程的积分,并结合这些来存档更高的精度。现在你可以看到,我已经对该功能进行了硬编码。是否可以读入数学方程并进行评估?我知道我可以在输入字符列表中读取然后评估函数(比如char [i] =='+'做....)但是有更简单的方法吗? 提前谢谢!

void Integral_TN (double* TN_ptr,double a,double b,int n,int my_rank,int p){
     int i;
     double a_loc;
     double b_loc;        
     double hN;

    *TN_ptr = 0;
     hN = (b-a)/n;

     a_loc = a + my_rank*n/p*hN;     
     b_loc = a + (my_rank+1)*n/p*hN;
    *TN_ptr += (function(a_loc)+function(b_loc))/2;     /*Evaluate f at the borders*/

     for(i = 1; i < n/p; i++){
          *TN_ptr += function(a_loc + i*hN);            /*Evaluate f at the inner nodes*/
     }
    *TN_ptr = *TN_ptr*hN;
}

double function(double x){
      double y;
      y = 1/(1+x*x);
      return y; 
}

2 个答案:

答案 0 :(得分:1)

您希望实现的目标没有更简单的方法。如果要将特定公式应用于某些值,则必须为其定义函数并输入值。

如果您希望输入整个表达式(使用值和运算符)作为输入并获得所需的结果作为输出,则必须超越基本编程。您需要创建一个解析器。

例如,如果您提供#container { overflow: hidden; } 作为输入,则可能需要3+2*4作为输出而不会读取单独的值1132。这可以通过在YACC之类的解析器生成器中实现自定义解析器来实现。基本上,您将创建和定义有关如何解释输入的新规则。

答案 1 :(得分:1)

skrtbhtngr已经回答了所述问题,但我想解决潜在的问题。

应用Unix philosophy。使用一个工具生成数据,使用另一个工具生成数据 - 这里,使用梯形规则计算积分。

您可以使用的最简单格式与Gnuplot支持的格式相同:

  • 忽略空行
  • #开头的行将被忽略,可用于评论
  • 每行定义一个样本

基本上,您可以使用

非常粗略地描述正弦曲线
#x  sin(x)
0.000  0.000000000
0.100  0.099833417
0.200  0.198669331
0.300  0.295520207
0.400  0.389418342
0.500  0.479425539
0.600  0.564642473
0.700  0.644217687
0.800  0.717356091
0.900  0.783326910
1.000  0.841470985
1.100  0.891207360
1.200  0.932039086
1.300  0.963558185
1.400  0.985449730
1.500  0.997494987
1.600  0.999573603
1.700  0.991664810
1.800  0.973847631
1.900  0.946300088
2.000  0.909297427
2.100  0.863209367
2.200  0.808496404
2.300  0.745705212
2.400  0.675463181
2.500  0.598472144
2.600  0.515501372
2.700  0.427379880
2.800  0.334988150
2.900  0.239249329
3.000  0.141120008
3.100  0.041580662
3.200 -0.058374143
3.300 -0.157745694
3.400 -0.255541102
3.500 -0.350783228
3.600 -0.442520443
3.700 -0.529836141
3.800 -0.611857891
3.900 -0.687766159
4.000 -0.756802495
4.100 -0.818277111
4.200 -0.871575772
4.300 -0.916165937
4.400 -0.951602074
4.500 -0.977530118
4.600 -0.993691004
4.700 -0.999923258
4.800 -0.996164609
4.900 -0.982452613
5.000 -0.958924275
5.100 -0.925814682
5.200 -0.883454656
5.300 -0.832267442
5.400 -0.772764488
5.500 -0.705540326
5.600 -0.631266638
5.700 -0.550685543
5.800 -0.464602179
5.900 -0.373876665
6.000 -0.279415498
6.100 -0.182162504
6.200 -0.083089403

你可以用eg。 awk生成,就像我做的那样:

awk 'BEGIN { printf "#x sin(x)\n" ; for (x=0.0; x<6.3; x+=0.1) printf "%.3f %11.9f\n", x, sin(x) }'

如果将其保存到文件(将> data.txt附加到上述命令),则可以使用

在Gnuplot中绘制它
plot "data.txt" using 1:2 notitle with lines

此类数据易于在C程序中读取。因为我只使用POSIX.1系统(Linux,BSD,macOS),而POSIX.1提供了非常有用的getline()函数 - 它允许你读取任意长度的行,动态分配足够大的缓冲区 - ,这个特殊的实现也需要POSIX.1支持。换句话说,除了Windows之外,它基本上可以在任何地方使用。

#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

/* Read x y(x) values, one pair per line, from a stream.
   The arrays are dynamically allocated, and pointers stored
   to *xptr and *yptr. The size of the arrays is stored at *nptr.
   They are initially cleared to NULL/zero.
   The function returns 0 if success, an errno error code otherwise:
      EINVAL:  Invalid function parameters
      EIO:     Read error
      ENOMEM:  Out of memory
      EBADMSG: Malformed line
*/
int read_xy(double **xptr, double **yptr, size_t *nptr, FILE *in)
{
    /* Line input buffer variables. */
    char   *line = NULL;
    size_t  size = 0;
    ssize_t len;

    /* Data array variables. */
    double *x = NULL;
    double *y = NULL;
    size_t  n = 0;    /* Entries in x[] and y[] */
    size_t  nmax = 0; /* Entries allocated */

    /* Temporary variables. */
    double  xval, yval, *newx, *newy;

    /* We clear the output parameters to NULL or zero,
       in case the caller is careless and does not check
       the return value. Clearing them ensures they do
       not contain garbage in such a case. */
    if (xptr)
        *xptr = NULL;
    if (yptr)
        *yptr = NULL;
    if (nptr)
        *nptr = 0;

    /* We need in and nptr, and at least one of xptr and yptr. */
    if (!in || !nptr || (!xptr && !yptr))
        return errno = EINVAL;

    /* If an error has already occurred in 'in',
       we do not even try to read from it. */
    if (ferror(in))
        return EIO;

    while (1) {

        /* Read next input line. */
        len = getline(&line, &size, in);

        /* End of input or error? */
        if (len < 0)
            break;

        /* Skip empty and comment lines. */
        if (len == 0 ||
            line[0] == '\n' || (line[0] == '\r' && line[1] == '\n') ||
            line[0] == '#')
            continue;

        /* Parse the line. */
        if (sscanf(line, " %lf %lf", &xval, &yval) != 2)
            break;

        /* Need to grow the dynamically allocated arrays? */
        if (n >= nmax) {

            /* Allocation policy.
               We allocate room for at least 16 doubles,
               then double the size up to 1048576 (=2^20),
               then adjust to the next full multiple of 1048576.
               This is not 'the best', but it is robust,
               and not too wasteful.
            */
            if (n < 16)
                nmax = 16;
            else
            if (n < 1048576)
                nmax = n * 2;
            else
                nmax = (n | 1048575) + 1048576;

            /* Note: realloc(NULL, size) is equivalent to malloc(size).
               If the realloc() call fails, it returns NULL,
               but the original array is still valid.
               Also note that free(NULL) is safe, and does nothing.
            */
            newx = realloc(x, nmax * sizeof x[0]);
            newy = realloc(y, nmax * sizeof y[0]);
            if (newx)
                x = newx;
            if (newy)
                y = newy;
            if (!newx || !newy) {
                /* One or both of the allocations failed. */
                free(line);
                free(x);
                free(y);
                return ENOMEM;
            }
        }

        /* Save the parsed values to the arrays. */
        x[n] = xval;
        y[n] = yval;
        n++;
    }

    /* We no longer need the line buffer. */
    free(line);

    /* Did a read error occur? */
    if (ferror(in)) {
        free(x);
        free(y);
        return EIO;
    }

    /* Was there no data to read? */
    if (n < 1) {
        free(x);
        free(y);
        return 0;
    }

    /* Reallocate the arrays to their exact sizes
       (actually, allow for one extra double at the end,
        because it is often useful to copy the initial
        ones there if the data is considered cyclic).
    */
    nmax = n + 1; /* One extra just because it is so often useful. */
    newx = realloc(x, nmax * sizeof x[0]);
    newy = realloc(y, nmax * sizeof y[0]);
    if (newx)
        x = newx;
    if (newy)
        y = newy;
    if (!newx || !newy) {
        free(x);
        free(y);
        return ENOMEM;
    }

    /* Save the array pointers. */
    if (xptr)
        *xptr = x;
    else
        free(x);

    if (yptr)
        *yptr = y;
    else
        free(y);

    /* Save the number of samples read. */
    *nptr = n;

    /* If feof(in) is true, then we read everything
       up to end of input. Otherwise, we stopped at
       a line we could not parse.
    */   
    if (!feof(in))
        return EBADMSG;

    return 0;
}

该功能或类似的功能应该在每个数值计算课程的课程材料中。它们非常有用。除了系统管理员为每个进程设置的可能的内存分配限制之外,这个特定的数据对它可以读取的数据大小没有固有的限制。我知道,如果你有足够的RAM,它会成功地读取数十亿行数据。

使用该功能非常简单。下面是一个示例main(),它只是从标准输入中读取这些数据 - 记住您可以通过在运行它时将< file附加到命令来使其从文件中读取 - 并打印数据进行。

int main(void)
{
    double *x, *y;
    size_t  i, n;
    int     result;

    result = read_xy(&x, &y, &n, stdin);

    switch (result) {
    case 0: /* No errors */
        break;

    case EBADMSG:
        if (n > 1)
            fprintf(stderr, "Invalid line after %zu data samples.\n", n);
        else
            fprintf(stderr, "Cannot parse first input line.\n");
        return EXIT_FAILURE;

    case ENOMEM:
        fprintf(stderr, "Out of memory.\n");
        return EXIT_FAILURE;

    case EIO:
        fprintf(stderr, "Read error.\n");
        return EXIT_FAILURE;

    case EINVAL:
        fprintf(stderr, "Invalid parameters to the read_xy() function!\n");
        return EXIT_FAILURE;

    default:
        fprintf(stderr, "%s.\n", strerror(result));
        return EXIT_FAILURE;
    }

    printf("Read %zu samples:\n", n);
    for (i = 0; i < n; i++)
        printf("%.9f %.9f\n", x[i], y[i]);

    return EXIT_SUCCESS;
}

请注意,大多数是switch (result) { .. }错误报告代码。如果发生错误,此示例非常谨慎地告诉您;原因是,作为用户,你需要知道程序何时知道它们可能会喷出垃圾,并且在现实生活中会更喜欢程序中止而不是默默地喷出垃圾 - 也许会让你相信它是有效的。

虽然可以修改上述代码甚至可以在Windows上运行(例如,将getline()替换为fgets(),并希望您使用的缓冲区大小就足够了;并且也可能需要更改一些errno错误代码)。但是,500强超级计算机列表中没有Windows机器是有原因的:POSIXy系统(Unix和Linux)更适合科学计算。所以,如果你打算在某些科学计算上工作,你可以设置一个Linux或BSD虚拟机,并在那里进行开发。