Finding derivative of a function stored in a character array

耗尽温柔 提交于 2019-12-02 09:37:29
A. Abramov

What you're really asking for is a parser. A parser is basically a set of rules to read those equations and change/read (parse) each of them. I'd try to iterate over each line of the file, and differentiate it considering you have a specific character set (i.e ^ means power, x is the parameter, etc.);

For example, some pseudo code:

Open the file.
While there's lines to read:
   Read a line - 
   Seperate it by the operands (+,-,/,*)
   For each part:
     Find the power of x,
     Reduce it by one,
     ...(derivating rules) // no way around, you have to implement each function if you want this to work as others mentioned in the comments.
   Reconnect the parts into a string,
   Add it to a list.
 Print each element of the list.

If you need help translating that into C, just ask for it; I'll happily help you.

What you need to do, by the looks of things, is separate the expression into individual terms so that you can find the derivative of each in turn.

You can define a term as the largest sequence of characters not containing term separators such as (in your examples) + and -.

Hence the terms for your examples are:

-2x^2+2x-3     =>  2x^2  2x     3
-2x+sinx-3     =>  2x    sinx   3
-x+sin2x-tanx  =>  x     sin2x  tanx

For each term, you then need to evaluate the form of the term. The form will dictate how you create the derivative.


For example, you can detect if it contains a trigonometric function of the form [n]sin[m]x where n and m are optional numbers. To simplify things, you could add in those terms if they're not there, such as sinx becoming 1sin1x (I'll call this the full-form of the term). Being able to assume all subterms are present will greatly ease the derivative calculation.

Let's say the term is sin4x. Expanding that will give you 1sin4x which you can then split into term-multiplier 1, function sin and x-multiplier 4. Then using standard derivative knowledge nsinmx => (n*m)cosmx, this would become 4cos(4x) and that term would be done.


If it doesn't contain a trigonometric function, you can use the same full-form trick to cover all of the power/constant expressions with the following rules in turn:

  • if it's a constant (all numeric), append x^0 (multiply by 1).
  • if it ends with x, append ^1, so 4x becomes 4x^1.
  • if it starts with x, prefix it with 1, so x^3 becomes 1x^3.

Once that's done, you will have a full-form of ax^b and you can then create the derivative (ab)x^(b-1) and post-process it:

  • if the bit after x is ^0, remove the whole x^0.
  • if the bit after x is ^1, remove the ^1.
  • if the bit before the x is 1, remove it.
  • if the bit before the x is 0, remove the entire term (and preceding term separator, if any).

So, taking a complex combination of your test data:

-2x^2 + 5x + 4sin3x - 3

which can be treated as:

0 - 2x^2 + 5x + 4sin3x - 3

The following actions happen to each term:

0      [0x^1]   (derives as) 0, remove it.
2x^2   [2x^2]   (derives as) (2*2)x^(2-1) => 4x^1 => 4x
5x     [5x^1]   (derives as) (5x1)x^(1-1) => 5x^0 => 5
4sin3x [4sin3x] (derives as) 12cos3x
3      [3x^0]   (derives as) 0, remove it and preceding '-'

Thus you end up with - 4x + 5 + 12cos3x which, although my calculus education is some thirty years in the past (and I don't think I've used it since, though I will no doubt be using it next year when my eldest hits secondary school), Wolfram Alpha appears to agree with me :-)

This function will parse the text, cut it in to different parts identified by type[i], stores in a structure. It recognizes x, +, -, and numbers. It can be expand it to include other operators etc.

#define maxlen 50

#define idx         0 //X variable
#define idnumber    1 //number
#define idplus      2 //+ sign
#define idminus     3 //- sign

struct foo
{
    int type[10];//each type can be a number (idnum), +, -, etc.
    int num[10];//if type[i] is number then num[i] identifies that number
    int count;//total number of parts
};

void parse_one_line(struct foo *v, const char *s)
{
    char buf[maxlen];
    memset(buf, 0, maxlen);
    int j = 0;
    //remove white spaces
    for (int i = 0, len = strlen(s); i < len; i++)
    {
        if (s[i] == ' ') continue;
        buf[j] = s[i];
        j++;
    }

    char part[maxlen];
    v->count = 0;
    for (int i = 0, len = strlen(buf); i < len; i++)
    {
        char c = buf[i];
        if (c == 'x')
        {
            v->type[v->count] = idx;
            v->count++;
        }
        else if (c == '+')
        {
            v->type[v->count] = idplus;
            v->count++;
        }
        else if (c == '-')
        {
            v->type[v->count] = idminus;
            v->count++;
        }
        else if (c >= '0' && c <= '9')
        {
            int j = 0;
            memset(part, 0, maxlen);
            for (; i < len; i++)
            {
                c = buf[i];
                if (c >= '0' && c <= '9')
                {
                    part[j] = c;
                    j++;
                }
                else
                {
                    break;
                }
            }
            i--;
            v->num[v->count] = atoi(part);
            v->type[v->count] = idnumber;
            v->count++;
        }
    }
    for (int i = 0; i < v->count; i++)
    {
        switch (v->type[i])
        {
        case idnumber: printf("%d", v->num[i]); break;
        case idx: printf("X"); break;
        case idplus: printf("+"); break;
        case idminus: printf("-"); break;
        default:break;
        }
    }
    printf("\n");
}

int main()
{
    struct foo st;
    parse_one_line(&st, "-23x + 2 + 2x - 3");
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!