Aidez-moi avec le calcul différentiel!


52

J'adore programmer et je connais toutes les langues, mais je suis nul en maths. Malheureusement, mon école exige que les étudiants en informatique prennent une année de calcul. Il y a un test la semaine prochaine et je ne connais aucune des formules pour les dérivés!

S'il vous plaît aidez-moi à trouver les formules. J'ai besoin d'un aide-mémoire - un programme (aussi court que possible pour que mon enseignant ne le remarque pas) qui prend une expression (comme 4*x^3-2) comme entrée et génère le dérivé. (Je me moque de savoir si l'entrée et la sortie utilisent des arguments de ligne de commande, STDIN, STDOUT ou quoi que ce soit, puisque je fais tous les calculs dans ma tête, de toute façon.)

Le test couvre les types de fonctions suivants:

  • Constantes, comme -3ou8.5
  • Fonctions de puissance, comme x^0.5oux^-7
  • Fonctions exponentielles, comme 0.5^xou 7^x(la base est toujours positive)
  • Une constante multipliée par une fonction, comme 3*x^5ou-0.1*0.3^x
  • La somme et la différence de multiples fonctions, comme -5*x^2+10-3^x

Mon professeur formate toujours ses questions exactement de la même manière, comme indiqué ci-dessus. Il n'utilise pas non plus de fractions, de nombres tels que pi ou e , ni de très gros nombres (plus de 1 000). Il n'utilise jamais de parenthèses et affiche toujours la multiplication à l'aide d'un astérisque ( *). La seule variable utilisée est toujours x .

D'autre part, mon professeur est assez indulgent sur les réponses. Ils n'ont pas du tout besoin d'être simplifiés ou formatés exactement comme indiqué ci-dessus, tant que la réponse est claire.

Bien que je puisse utiliser n'importe quel langage, souvenez-vous que je ne peux pas comprendre les dérivés par moi-même. Donc, si le programme utilise des fonctions intégrées pour traiter des équations ou calculer des dérivées, je ne pourrai pas l'utiliser.

Pendant le test, je n’aurai pas accès à Internet ni à d’autres fichiers que le programme sur la feuille de triche.

Remarque: Ce scénario est entièrement fictif. Dans la vraie vie, tricher et aider les autres à tricher est une erreur et ne devrait jamais être fait.


3
Pouvons-nous nous attendre à ce que ce xsoit toujours la variable à différencier?
Kyle Kanos

2
La réponse doit-elle être simplifiée? Avons-nous besoin d'ajouter des termes similaires?
Rainbolt

1
Je pense qu'il est temps que mon projet de calcul sur scrblnrd3.github.io/Javascript-CAS brille si je peux réellement
jouer au

1
Devrions-nous supposer qu'il n'y a pas de parens?
Pas que Charles

2
J'ai répondu à la plupart de ces questions dans ma rédaction . Il n'y a pas de notation scientifique ou de règle de produit.
Ypnypn

Réponses:


8

Wolfram 136 134 109 [Merci à Calle pour son commentaire ci-dessous]

Prise en charge limitée des règles de produit et de chaîne.

n=n_?NumberQ;d[v_Plus]:=d/@v;d[v_]:=v/.{x_^n:>x^(n-1)d[x]n,n^x_:>Log[n]d[x]n^x,x_*y__:>d[x]y+d[y]x,n:>0,x:>1}

Exemple:

d[3^(x^2)*(x^3+2*x)^2]
>> 2*3^x^2*(2+3*x^2)*(2*x+x^3) + 2*3^x^2*x*(2*x+x^3)^2*Log[3]

Notez que cela n'utilise aucune "fonction intégrée pour traiter des équations ou calculer des dérivées": seul le filtrage par motif est impliqué *.

[* Bien ... techniquement, l'interprète analyse et construit également une sorte d'AST à partir de l'entrée]


Ungolfed:

d[expr_Plus] := d /@ expr;
d[expr_] := expr /. {
   Power[x_, n_?NumberQ] :> n Power[x, n - 1] d[x],
   Power[n_?NumberQ, x_] :> Log[n] Power[n, x] d[x],
   Times[x_, y__] :> d[x] y + d[y] x,
   n_?NumberQ :> 0,
   x :> 1
}

Ceci est une autre version . Vous n'êtes pas obligé d'écrire Power, Timesetc. IDK, dans quelle mesure cela améliorera votre version jouée au golf, mais vous en avez au moins un Timespour que vous puissiez jouer. sauver des personnages. Notez également que dans votre version non-lue, il est écrit d[expr_]:= v/....

1
@Calle "IDK combien cela va améliorer votre version jouée au golf" - 25 octets! À votre santé!
Saran

26

Perl - 121 122

(+2 pour -p)

s/(?<![-\d.*^])-?[\d.]+(?![*^\d.])/0/g;s/(?<!\^)x(?!\^)/1/g;s/x\^(-?[\d.]+)/"$1*x^".($1-1)/ge;s/([\d.]+)\^x/ln($1)*$&/g

Tester:

$ perl -p diff.pl << EOF
> -3
> 8.5
> x^0.5
> x^-7
> 0.5^x
> 7^x
> 3*x^5
> -0.1*0.3^x
> -5*x^2+10-3^x
> EOF
0
0
0.5*x^-0.5
-7*x^-8
ln(0.5)*0.5^x
ln(7)*7^x
3*5*x^4
-0.1*ln(0.3)*0.3^x
-5*2*x^1+0-ln(3)*3^x

Encore une autre raison pour moi d'apprendre le regex ...
Kyle Kanos

3
@KyleKanos Ne pas. Regex est mauvais, regex est génial.
Mniip

Meh, bats-moi. Pas mal! (PS: regex is beautiful)
Martin Ender

8
Je n'ai aucune idée de ce qui se passe ici. +1
qwr

4
Explication: Constante -> 0, x -> 1, x ^ n -> n * x ^ (n-1), a ^ x -> ln (a) * a ^ x
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

7

Haskell 38 Chars

La fonction dprend une fonction et retourne une fonction. Il est entré sous la forme d'une série de puissance et est émis de la même manière (ce qui est un type de tout.)

d=zipWith(*)[1..].tail

Par exemple, si nous entrons x->x^2, nous obtenons x->2*x.

λ <Prelude>: d [0,0,1]
[0,2]

Et pour la fonction exponentielle.

λ <Prelude>: take 10 exp --exp redefined above to be in power series notation
[1.0,1.0,0.5,0.16666666666666666,4.1666666666666664e-2,8.333333333333333e-3,1.388888888888889e-3,1.984126984126984e-4,2.48015873015873e-5,2.7557319223985893e-6]
λ <Prelude>: let d=zipWith(*)[1..].tail in take 10 $ d exp
[1.0,1.0,0.5,0.16666666666666666,4.1666666666666664e-2,8.333333333333333e-3,1.388888888888889e-3,1.984126984126984e-4,2.48015873015873e-5,2.7557319223985893e-6]

5
Mais le PO ne connaît pas de maths! Peut-on s’attendre à ce qu’il exprime son entrée exponentielle en tant que série de puissance?
Saran

Eh bien, il connaît évidemment la notation. Il ne sait tout simplement pas comment faire l'opération dérivée.
PyRulez

5
Ça peut gérer 2^x?
Kyle Kanos

5
De quelle sorcellerie s'agit-il?
Christofer Ohlsson

7
Je ne vois pas où il "prend une expression (comme 4*x^3-2) en tant qu'entrée", comme requis par l'OP.
Gabe

5

Prolog 176

d(N,0):-number(N).
d(x,1).
d(-L,-E):-d(L,E).
d(L+R,E+F):-d(L,E),d(R,F).
d(L-R,E-F):-d(L,E),d(R,F).
d(L*R,E*R+L*F):-d(L,E),d(R,F).
d(L^R,E*R*L^(R-1)+ln(L)*F*L^R):-d(L,E),d(R,F).

Opérateurs pris en charge: binaire +, binaire -, binaire *, binaire ^, unaire -. Notez que le unary +n'est pas supporté.

Échantillon échantillon:

49 ?- d(-3,O).
O = 0.

50 ?- d(8.5,O).
O = 0.

51 ?- d(x^0.5,O).
O = 1*0.5*x^ (0.5-1)+ln(x)*0*x^0.5.

52 ?- d(x^-7,O).
ERROR: Syntax error: Operator expected
ERROR: d(x
ERROR: ** here **
ERROR: ^-7,O) . 
52 ?- d(x^ -7,O).
O = 1* -7*x^ (-7-1)+ln(x)*0*x^ -7.

53 ?- d(x,O).
O = 1.

54 ?- d(0.5^x,O).
O = 0*x*0.5^ (x-1)+ln(0.5)*1*0.5^x.

55 ?- d(7^x,O).
O = 0*x*7^ (x-1)+ln(7)*1*7^x.

56 ?- d(3*x^5,O).
O = 0*x^5+3* (1*5*x^ (5-1)+ln(x)*0*x^5).

57 ?- d(-0.1*0.3^x,O).
O = 0*0.3^x+ -0.1* (0*x*0.3^ (x-1)+ln(0.3)*1*0.3^x).

58 ?- d(-5*x^2+10-3^x,O).
O = 0*x^2+ -5* (1*2*x^ (2-1)+ln(x)*0*x^2)+0- (0*x*3^ (x-1)+ln(3)*1*3^x).

Prolog est confus quand il se met en ^-séquence. Un espace doit être inséré entre ^et -pour analyser correctement l'expression.

J'espère que votre professeur ne craint pas le désordre de l'équation.

Temps fou:

59 ?- d(x^x,O).
O = 1*x*x^ (x-1)+ln(x)*1*x^x.

60 ?- d((x^2-x+1)*4^ -x,O).
O = (1*2*x^ (2-1)+ln(x)*0*x^2-1+0)*4^ -x+ (x^2-x+1)* (0* -x*4^ (-x-1)+ln(4)* - 1*4^ -x).

4

C, 260

Hé, je pense connaître votre professeur! N'est-ce pas celui qui a la capacité surnaturelle de détecter les étudiants qui exécutent des fonctions de filtrage de bibliothèque dans leur tête?

Donc, utiliser sscanfest hors de question ... Mais ne vous inquiétez pas:

#define P s--||printf(
q=94,s,c,t,a;main(){char i[999],*p=i,*e=p;gets(i);for(;c=*p++,t=q^94|c^45?c%26==16?c%16/3:c/46:1,s=(a="30PCqspP#!C@ #cS` #!cpp#q"[s*5+t])/16-3,a&1&&(p[-1]=0),t||(P"*0"),P"/x"),P"/x*%s",e),P"*ln(%s)",e),s=0),a&2&&(e=p),c;putchar(q=c));}

Exemples courants (entrée sur stdin; sortie va à stdout):

4 * x ^ 3-2

4*x^3/x*3-2*0

Ce format est bien meilleur que juste 12*x^2, car votre professeur peut ainsi être sûr que vous avez calculé la réponse vous-même et que vous n'avez pas triché en la copiant de quelqu'un d'autre!

x + 2 ^ x

x/x+2^x*ln(2)

La sortie a un léger problème de domaine à x=0, mais elle est correcte presque partout !

Pour référence, voici une version non-lue, lisible (par de simples mortels). Il utilise une machine à états avec 5 états et 5 catégories de caractères saisis.

void deriv(char* input)
{
    char* p = input; // current position
    char* exp = p; // base or exponent
    char q = '^'; // previous character

    // State machine has 5 states; here are examples of input:
    // state 0: 123
    // state 1: 123*
    // state 2: 123*x
    // state 3: 123*x^456
    // state 4: 123^x
    int state = 0;

    // Control bits for state machine:
    // bit 0: special action: stop recording base or exponent
    // bit 1: special action: start recording base or exponent
    // bits 4-7: if first column, specify how to calculate the derivative:
    //              3 - multiply the constant term by 0
    //              4 - divide x by x
    //              5 - divide x^n by x and multiply by n
    //              6 - multiply n^x by ln(n)
    // bits 4-7: if not first column, specify the next state
    //              (plus 3, to make the character printable)
    const char* control =
        "\x33\x30\x50\x43\x71"
        "\x73\x70\x50\x23\x21"
        "\x43\x40\x20\x23\x63"
        "\x53\x60\x20\x23\x21"
        "\x63\x70\x70\x23\x71";

    for (;;) {
        int c = *p++;

        // Convert a char to a category:
        // category 0: // - +
        // category 3: // *
        // category 2: // x
        // category 4: // ^
        // category 1: // numbers: 0...9 and decimal point
        int category;
        int action;    

        if (q == '^' && c == '-')
            category = 1; // unary minus is a part of a number
        else
            category = c%26==16?c%16/3:c/46; // just does it

        // Load new state and action to do
        action = control[state * 5 + category];

        if (action & 1)
            p[-1] = 0;
        state = (action >> 4) - 3;
        if (category == 0)
        {
            if (state == 0)
                printf("*0");
            if (state == 1)
                printf("/x");
            if (state == 2)
                printf("/x*%s", exp);
            if (state == 3)
                printf("*ln(%s)", exp);
            state = 0;
        }
        if (action & 2)
            exp = p;

        if (c == 0 || c == '\n') // either of these can mark end of input
            break;

        putchar(c);
        q = c;
    }
}

PS Méfiez-vous de cette getsfonction: elle comporte une faille de sécurité qui peut permettre à votre enseignant d’exécuter un rootkit dans votre esprit en fournissant des informations trop longues ...


3

Lua 296 268 263

function d(a)l=""i=a:find"x" if i then if a:sub(i-1,i-1)=="^"then l="log("..a:sub(1,i-2)..")*"..a elseif a:sub(i+1,i+1)=="^"then l=a:sub(i+2).."*"..a:sub(1,i)p=a:sub(i+2)-1 if p~=1 then l= l..a:sub(i+1,i+1)..p end else l=a:sub(1,i-2)end else l="0"end return l end

Pas très golfed et ne peut pas gérer actuellement plusieurs termes (vous pouvez simplement le laisser tourner quelques fois, non?), Mais il peut gérer n^x, x^net ncomme entrée.


Ungolfed ...

function d(a)
   l=""
   i=a:find"x"
   if i then
      if a:sub(i-1,i-1)=="^" then
         l="log("..a:sub(1,i-2)..")*"..a
      elseif a:sub(i+1,i+1)=="^" then
         l=a:sub(i+2).."*"..a:sub(1,i)
         p=a:sub(i+2)-1 -- this actually does math here
         if p~=1 then
            l= l..a:sub(i+1,i+1)..p
         end
      else
         l=a:sub(1,i-2)
      end
   else
      l="0"
   end
   return l
end

str.func(str,...)== str:func(...), c'est pour cette raison que les cordes ont le pouvoir d'être méticulées après tout ...
mniip

@mniip: J'apprends toujours Lua. Merci pour le conseil.
Kyle Kanos

1
Puisque l'OP ne recherche que le code "il peut calculer dans sa tête", je ne me soucierais pas de définir une fonction et de déclarer llocal. Attendez-vous simplement à ce que l'entrée soit stockée aet dites que la sortie le sera l.
Martin Ender

Vous pouvez omettre les parenthèses dans a:find("x"), notez également que 1thenne fonctionne que dans Lua 5.2
mniip

@mniip: Whoa, c'est plutôt cool, c'est ()optionnel. Le 1thenproblème a été corrigé car je n'ai pas la version 5.2 (ne pas effectuer de mises à jour de la CPU avant la fin de la thèse, car je ne veux rien gâcher).
Kyle Kanos

3

ECMAScript 6, 127 octets

Voici ma tentative d'expression régulière (en utilisant une seule expression rationnelle et une certaine logique dans le rappel de remplacement):

i.replace(/(^|[*+-])(\d+|(?:([\d.]+)\^)?(x)(?:\^(-?[\d.]+))?)(?![.*^])/g,(m,s,a,b,x,e)=>s+(b?'ln'+b+'*'+a:e?e--+'*x^'+e:x?1:0))

Ceci attend que la chaîne d'entrée soit stockée iet renvoie simplement le résultat. Essayez-le dans une console compatible ECMAScript 6 (comme celle de Firefox).


2

sed, 110

Prendre très littéralement "Ils n'ont pas besoin d'être simplifiés ou formatés exactement comme indiqué ci-dessus, tant que la réponse est claire":

s/.*/__&_/;s/x\^(-?[0-9.]+)/\1*x^(\1-1)/g;s/([0-9.]+)\^/ln\1*\1^/g;s/([^(][-+_])[0-9.]+([-+_])/\10\2/g;s/_//g

Le nombre d'octets comprend 1 pour le rdrapeau.

Ungolfed, avec des commentaires:

# Add underscores before and after the string, to help with solo-constant recognition
s/.*/__&_/
# Power rule: replace x^c with c*x^(c-1) where c is a number
s/x\^(-?[0-9.]+)/\1*x^(\1-1)/g
# Exponentials: replace c^ with lnc*c^ where c is a number
# (This assumes that there will be an x after the ^)
s/([0-9.]+)\^/ln\1*\1^/g
# Constants: replace ?c? with ?0? where c is a number and ? is +, -, or _
# Except if it's prededed by a parenthesis then don't, because this matches c*x^(c-1)!
s/([^(][-+_])[0-9.]+([-+_])/\10\2/g
# Get rid of the underscores
s/_//g

Échantillon échantillon:

$ cat derivatives.txt
-3
8.5
x^0.5
x^-7
0.5^x
7^x
3*x^5
-0.1*0.3^x
-5*x^2+10-3^x

$ sed -re 's/.*/__&_/;s/x\^(-?[0-9.]+)/\1*x^(\1-1)/g;s/([0-9.]+)\^/ln\1*\1^/g;s/([^(][-+_])[0-9.]+([-+_])/\10\2/g;s/_//g' derivatives.txt
-0
0
0.5*x^(0.5-1)
-7*x^(-7-1)
ln0.5*0.5^x
ln7*7^x
3*5*x^(5-1)
-0.1*ln0.3*0.3^x
-5*2*x^(2-1)+0-ln3*3^x

Je parie que cela pourrait être joué au golf plus loin; c'est mon premier essai à sed. Amusement!


1

Ruby, 152

... ou 150 si vous n'avez pas besoin d'imprimer ... ou 147 si vous êtes également d'accord avec un tableau que vous devez rejoindre vous-même.

courir avec ruby -nal

p gsub(/(?<!\^)([-+])/,'#\1').split(?#).map{|s|s[/x\^/]?$`+$'+"x^(#{$'}-1)":s[/-?(.*)\^(.*)x/]?s+"*ln(#{$1}*#{$2[0]?$2:1})":s[/\*?x/]?($`[0]?$`:1):p}*''

ungolfed:

p gsub(/(?<!\^)([-+])/,'#\1').split(?#). # insert a # between each additive piece, and then split.
map{ |s|                                 
    if s[/x\^/]                          # if it's c*x^a
        $` + $' + "x^(#{$'}-1)"          #      return c*ax^(a-1)
    elsif s[/-?(.*)\^(.*)x/]             # if it's c*b^(a*x)
        ln = $1 + ?* + ($2[0] ? $2 : 1)  #      return c*b^(a*x)*ln(b*a)
        s+"*ln(#{ln})"
    elsif s[/\*?x/]                      # if it's c*x
        ($`[0] ? $` : 1)                 #      return c
    else                                 # else (constant)
        nil                              #      return nil
    end
}*''

Mon problème principal avec celui-ci est le nombre de caractères que la scission appropriée prend. La seule autre façon à laquelle je pouvais penser était celle split(/(?<!\^)([-+])/)qui donne +et -comme leurs propres résultats. Des indices pour une meilleure solution?

De plus, y a-t-il un moyen plus rapide de retourner ssi ce n'est pas vide, mais sinon de revenir y? J'ai utilisé s[0]?y:s? En JS, je le ferais s||y, mais la ""vérité est en Ruby.


Est- ce qu'une affirmation préanalyse aide, comme suit: split(/(?<!\^)(?=[-+])/)?
DLosc
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.