Aiutami con il calcolo differenziale!


52

Adoro programmare e conoscere ogni lingua, ma faccio schifo in matematica. Sfortunatamente, la mia scuola richiede che gli studenti di computer debbano prendere un anno di calcolo. C'è un test la prossima settimana e non conosco nessuna delle formule per i derivati!

Aiutatemi a trovare le formule. Ho bisogno di un cheat sheet - un programma (il più breve possibile in modo che il mio insegnante non se ne accorga) che prenda un'espressione (come 4*x^3-2) come input e produca la derivata. (Non mi interessa se l'input e l'output utilizzano argomenti della riga di comando, STDIN, STDOUT o altro, dato che sto comunque eseguendo tutti i calcoli nella mia testa.)

Il test copre i seguenti tipi di funzioni:

  • Costanti, come -3o8.5
  • Funzioni di potenza, come x^0.5ox^-7
  • Funzioni esponenziali, come 0.5^xo 7^x(la base è sempre positiva)
  • Una costante moltiplicata per una funzione, come 3*x^5o-0.1*0.3^x
  • La somma e la differenza di più funzioni, come -5*x^2+10-3^x

Il mio insegnante formatta sempre le sue domande nello stesso identico modo, come mostrato sopra. Inoltre non usa frazioni, numeri come pi o e , o numeri veramente grandi (più grandi di 1.000). Non usa mai le parentesi e mostra sempre la moltiplicazione usando un asterisco ( *). L'unica variabile utilizzata è sempre x .

D'altra parte, il mio insegnante è piuttosto indulgente riguardo alle risposte. Non hanno bisogno di essere semplificati o formattati esattamente come mostrato sopra, purché sia ​​chiaro ciò che la risposta sta dicendo.

Mentre posso usare qualsiasi lingua, ricorda che non riesco a capire i derivati ​​da solo. Quindi, se il programma utilizza funzioni integrate per gestire equazioni o calcolare derivati, non sarò in grado di usarlo.

Durante il test, non avrò accesso a Internet o ai file diversi dal programma sul cheat sheet.

Nota: questo scenario è interamente immaginario. Nella vita reale, imbrogliare e aiutare gli altri a imbrogliare è sbagliato e non dovrebbe mai essere fatto.


3
Possiamo aspettarci che xsia sempre la variabile a differenziare?
Kyle Kanos,

2
La risposta deve essere semplificata? Dobbiamo aggiungere termini simili?
Rainbolt,

1
Immagino sia giunto il momento per il mio progetto di calcolo su scrblnrd3.github.io/Javascript-CAS di brillare se posso davvero giocare a golf
scrblnrd3

1
Dovremmo presumere che non ci siano genitori?
Non che Charles,

2
Ho risposto alla maggior parte di queste domande nella mia modifica . Non esiste una notazione scientifica o una regola del prodotto.
Ypnypn,

Risposte:


8

Wolfram 136 134 109 [Grazie a Calle per il suo commento qui sotto]

Supporto limitato per le regole del prodotto e della catena.

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}

Esempio:

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]

Si noti che questo non utilizza alcuna "funzione incorporata per gestire equazioni o calcolare derivate": è coinvolto solo il pattern-matching *.

[* Beh ... tecnicamente l'interprete analizza e costruisce anche una sorta di AST dall'input]


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
}

Questa è un'altra versione . Non devi scrivere Power, Timesecc. IDK di quanto migliorerà la tua versione golfizzata, ma ne hai almeno una Timesin modo da poter def. salva alcuni personaggi. Nota anche che nella tua versione non golfata dice d[expr_]:= v/....

1
@Calle "IDK di quanto migliorerà la tua versione giocata a golf" - 25 byte! Saluti!
Saran,

26

Perl - 121 122

(+2 per -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

Test:

$ 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

Ancora un altro motivo per cui ho imparato regex ...
Kyle Kanos,

3
@KyleKanos Don't. Regex è male, regex è eccezionale.
mniip,

Meh, battimi. Non male! (PS: regex è bellissimo)
Martin Ender,

8
Non ho idea di cosa stia succedendo qui. +1
qwr

4
Spiegazione: Costante -> 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 funzione daccetta una funzione e restituisce una funzione. Viene immesso nella forma di una serie di potenze e viene emesso allo stesso modo (che è un tipo di qualunque cosa).

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

Ad esempio, se inseriamo x->x^2, otteniamo x->2*x.

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

E per la funzione esponenziale.

λ <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
Ma l'OP non conosce matematica! Possiamo aspettarci che esprima il suo contributo esponenziale come una serie di potenze?
Saran,

Beh, ovviamente conosce la notazione. Semplicemente non sa come eseguire l'operazione derivata.
PyRulez,

5
Questo può gestire 2^x?
Kyle Kanos,

5
Che stregoneria è questa?
Christofer Ohlsson,

7
Non vedo dove "accetta un'espressione (come 4*x^3-2) come input", come richiesto dall'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).

Operatori supportati: binario +, binario -, binario *, binario ^, unario -. Si noti che unario +non è supportato.

Esecuzione di esempio:

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 è confuso quando viene eseguito in ^-sequenza. È necessario inserire uno spazio tra ^e -affinché analizzi correttamente l'espressione.

Spero che il tuo insegnante non si preoccupi del disordine dell'equazione.

Tempo pazzo:

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

Ehi, penso di conoscere il tuo insegnante! Non è quello che ha la capacità soprannaturale di rilevare gli studenti che eseguono funzioni di abbinamento dei modelli della biblioteca nella loro testa?

Quindi, l'utilizzo sscanfè fuori discussione ... Ma non preoccuparti:

#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));}

Esempi in esecuzione (input on stdin; output va a stdout):

4 * x ^ 3-2

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

Questo formato è molto meglio del semplice 12*x^2, perché in questo modo il tuo insegnante può essere sicuro di aver calcolato la risposta da solo e di non aver imbrogliato copiandolo da qualcun altro!

x + 2 ^ x

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

L'output ha un leggero problema di dominio x=0, ma è corretto quasi ovunque !

Per riferimento, ecco una versione non giocata, leggibile (da semplici mortali). Utilizza una macchina a stati con 5 stati e 5 categorie di caratteri di input.

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 Fai attenzione a quella getsfunzione: ha una vulnerabilità di sicurezza che può consentire al tuo insegnante di eseguire un rootkit nella tua mente fornendo un input troppo lungo ...


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

Non molto giocato a golf e non può attualmente gestire più termini (si può semplicemente eseguire un paio di volte, giusto?), Ma è in grado di gestire n^x, x^ne ncome input.


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(...), ecco perché le stringhe sono diventate metabili dopo tutto ...
mniip,

@mniip: sto ancora imparando Lua. Grazie per il consiglio.
Kyle Kanos,

1
Dato che l'OP sta cercando solo il codice "può calcolare nella sua testa", non mi preoccuperei di definire una funzione e dichiarare llocale. Aspettatevi solo che l'input venga archiviato ae dite che l'output verrà archiviato l.
Martin Ender,

Puoi omettere le parentesi a:find("x"), nota anche che 1thenfunziona solo in Lua 5.2
mniip,

@mniip: Whoa, è abbastanza bello che ()è facoltativo. Il 1thenproblema è stato appena risolto in quanto non ho 5.2 (non eseguendo alcun aggiornamento della CPU fino a quando la tesi non è terminata in b / c non voglio rovinare nulla).
Kyle Kanos,

3

ECMAScript 6, 127 byte

Ecco il mio tentativo di regex (usando un singolo regex e un po 'di logica nel callback sostitutivo):

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))

Questo si aspetta che la stringa di input sia archiviata ie restituisce semplicemente il risultato. Provalo in una console conforme a ECMAScript 6 (come quella di Firefox).


2

sed, 110

Prendendo molto alla lettera "Non è necessario che siano affatto semplificati o formattati esattamente come mostrato sopra, purché sia ​​chiaro cosa dice la risposta":

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

Il conteggio dei byte include 1 per il rflag.

Ungolfed, con commenti:

# 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

Esecuzione di esempio:

$ 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

Scommetto che questo potrebbe essere ulteriormente golfato; è il mio primo tentativo a sed. Divertimento!


1

Ruby, 152

... o 150 se non hai bisogno di stampare ... o 147 se stai bene anche con un array che devi unire a te stesso.

Corri con 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
}*''

Il mio problema principale con questo è il numero di caratteri necessari per la divisione corretta. L'unico altro modo a cui potevo pensare era quello split(/(?<!\^)([-+])/)che dà +e -come i loro risultati. Qualche suggerimento per una soluzione migliore?

Inoltre, c'è un modo più breve per tornare sse non è vuoto, ma altrimenti tornare y? Ho usato s[0]?y:s? In JS lo farei s||y, ma ""è vero in Ruby.


Sarebbe un aiuto asserzione che guarda avanti, in questo modo: split(/(?<!\^)(?=[-+])/)?
DLosc,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.