2016-11-19 48 views
0

目前,我正在編寫一個程序,通過使用梯形法則和它們的組合來計算方程的積分以存檔更高的精度。現在您可以在下面看到,我已經對函數進行了硬編碼。是否可以讀入數學方程式並對其進行評估?我知道我可以在輸入字符列表中讀取,然後評估函數(就像char [i] =='+'做的那樣),但是有沒有更簡單的方法? 提前謝謝!C從命令行讀取數學公式

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

也許有另一個去格式化代碼,並使其更具可讀性。 PS什麼_感謝你的優勢_是什麼意思? –

+0

完成。重要的部分是功能「功能」。現在這個函數是硬編碼的,我想把它作爲一個參數來讀取,例如從命令行。 – Noveel

+0

聽起來像你需要一個解析器。 – EOF

回答

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 

你可以使用例如。 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; 
} 

該函數或類似的東西應該在每個數值計算課程的課程材料中。他們只是非常有用。除了系統管理員爲每個進程設置的可能的內存分配限制以外,這個特定的內存對它可以讀取的數據的大小沒有固有的限制。我知道一個事實,即如果你只有足夠的內存,它可以成功讀取數十億行數據。

使用該功能非常簡單。以下是一個示例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)。然而,在Top 500超級計算機列表中沒有Windows機器是有原因的:POSIXy系統(Unix和Linux)更適合科學計算。所以,如果你打算開展一些科學計算,那麼你可能只需要建立一個Linux或BSD虛擬機,然後在那裏進行開發。

+0

謝謝你的依靠幫助我作爲一個起點。由於我使用Kubuntu無論如何,我不必更改代碼。 – Noveel

1

沒有簡單的方法來實現您的目標。如果您想要將特定公式應用於某些值,則必須爲其定義一個函數並輸入值。

如果您希望輸入整個表達式(包含值和運算符)作爲輸入並獲得所需的結果作爲輸出,則必須超出基本編程範圍。你需要創建一個解析器。

舉例來說,如果你提供3+2*4作爲輸入,你可能期望11爲輸出而沒有單獨的值324閱讀。這可以通過在解析器生成器(如YACC)中實現自定義解析器來實現。基本上,您將創建並定義關於如何解釋輸入的新規則。

+0

...你需要定義你的語言來表達數學的單行。 –

+0

不一定@PaulOgilvie。 – skrtbhtngr