¡Ayúdame con el cálculo diferencial!

52

Me encanta la programación y sé todos los idiomas, pero soy muy malo en matemáticas. Desafortunadamente, mi escuela requiere que los estudiantes de computación tomen un año de cálculo. ¡Hay una prueba la próxima semana, y no conozco ninguna de las fórmulas para derivados!

Por favor, ayúdame a encontrar las fórmulas. Necesito una hoja de trucos: un programa (lo más corto posible para que mi maestro no lo note) que toma una expresión (como 4*x^3-2) como entrada y genera la derivada. (No me importa si la entrada y la salida usan argumentos de línea de comando, STDIN, STDOUT o lo que sea, ya que de todos modos estoy haciendo todo el cálculo en mi cabeza).

La prueba cubre los siguientes tipos de funciones:

  • Constantes, como -3o8.5
  • Funciones de potencia, como x^0.5ox^-7
  • Funciones exponenciales, como 0.5^xo 7^x(la base siempre es positiva)
  • Una constante multiplicada por una función, como 3*x^5o-0.1*0.3^x
  • La suma y diferencia de múltiples funciones, como -5*x^2+10-3^x

Mi maestro siempre formatea sus preguntas exactamente de la misma manera, como se muestra arriba. Tampoco usa fracciones, números como pi o e , o números realmente grandes (más de 1,000). Él nunca usa paréntesis, y siempre muestra multiplicación usando un asterisco ( *). La única variable utilizada es siempre x .

Por otro lado, mi maestro es bastante indulgente con las respuestas. No necesitan simplificarse ni formatearse exactamente como se muestra arriba, siempre que esté claro lo que dice la respuesta.

Si bien puedo usar cualquier idioma, recuerde que no puedo encontrar derivados por mí mismo. Entonces, si el programa usa funciones incorporadas para tratar ecuaciones o calcular derivadas, no podré usarlo.

Durante la prueba, no tendré acceso a Internet ni a ningún archivo que no sea el programa en la hoja de trucos.

Nota: Este escenario es completamente ficticio. En la vida real, hacer trampa y ayudar a otros a hacer trampa está mal y nunca se debe hacer.

Ypnypn
fuente
3
¿Podemos esperar que esa xsea ​​siempre la variable para diferenciar?
Kyle Kanos
2
¿Se debe simplificar la respuesta? ¿Necesitamos agregar términos similares?
Rainbolt
1
Creo que es hora de que mi proyecto de cálculo en scrblnrd3.github.io/Javascript-CAS brille si realmente puedo jugar golf
scrblnrd3
1
¿Debemos suponer que no hay padres?
No es que Charles
2
He respondido la mayoría de estas preguntas en mi edición . No hay notación científica o regla de producto.
Ypnypn

Respuestas:

8

Wolfram 136 134 109 [Gracias a Calle por su comentario a continuación]

Soporte limitado para reglas de productos y cadenas.

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}

Ejemplo:

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]

Tenga en cuenta que esto no utiliza ninguna "función incorporada para tratar ecuaciones o calcular derivadas": solo interviene la coincidencia de patrones *.

[* Bueno ... técnicamente, el intérprete también analiza y crea una especie de AST a partir de la entrada también]


Sin golf:

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
}
Saran
fuente
Esta es otra versión . No tiene que escribir Power, Timesetc. IDK, sin embargo, cuánto mejorará su versión de golf, pero tiene al menos uno Timesallí para que pueda definir. guardar algunos personajes También tenga en cuenta que en su versión sin golf dice d[expr_]:= v/....
1
@Street "IDK cuánto mejorará su versión de golf" - ¡25 bytes! ¡Salud!
Saran
26

Perl - 121 122

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

Prueba:

$ 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
mniip
fuente
Otra razón más para que yo aprenda regex ...
Kyle Kanos
3
@KyleKanos No lo hagas. Regex es malo, regex es excelente.
mniip
Meh, venceme. ¡No está mal! (PD: regex es hermoso)
Martin Ender
8
No tengo idea de lo que está pasando aquí. +1
qwr
44
Explicación: 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 función dtoma una función y devuelve una función. Se ingresa en forma de serie de potencia y se emite de la misma manera (que es un tipo de lo que sea).

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

Por ejemplo, si ingresamos x->x^2, obtenemos x->2*x.

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

Y para la función exponencial.

λ <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]
PyRulez
fuente
55
¡Pero el OP no sabe nada de matemáticas! ¿Podemos esperar que exprese su entrada exponencial como una serie de potencia?
Saran
Bueno, obviamente él sabe notación. Simplemente no sabe cómo hacer la operación derivada.
PyRulez
55
¿Puede esto manejar 2^x?
Kyle Kanos
55
¿Qué brujería es esta?
Christofer Ohlsson
77
No veo dónde "toma una expresión (como 4*x^3-2) como entrada", como lo requiere el 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).

Operadores admitidos: binario +, binario -, binario *, binario ^, unario -. Tenga en cuenta que unary +no es compatible.

Ejecución de muestra:

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 se confunde cuando se ejecuta en ^-secuencia. Se debe insertar un espacio entre ^y -para que pueda analizar la expresión correctamente.

Espero que a tu maestro no le importe el lío de la ecuación.

Tiempo loco:

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).
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
fuente
4

C, 260

¡Hola, creo que conozco a tu maestra! ¿No es aquel que tiene la capacidad sobrenatural de detectar estudiantes que ejecutan funciones de coincidencia de patrones de biblioteca en su cabeza?

Entonces, el uso sscanfestá fuera de discusión ... Pero no se preocupe:

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

Ejecución de ejemplos (entrada encendida stdin; la salida va a stdout):

4 * x ^ 3-2

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

¡Este formato es mucho mejor que solo 12*x^2, porque de esta manera su maestro puede estar seguro de que calculó la respuesta usted mismo y no hizo trampa al copiarla de otra persona!

x + 2 ^ x

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

La salida tiene un pequeño problema de dominio x=0, ¡pero es correcta en casi todas partes !

Como referencia, aquí hay una versión no legible, legible (por simples mortales). Utiliza una máquina de estados con 5 estados y 5 categorías de caracteres de entrada.

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

PD Tenga cuidado con esa getsfunción: tiene una vulnerabilidad de seguridad que puede permitir que su maestro ejecute un rootkit en su mente al proporcionar información demasiado larga ...

anatolyg
fuente
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

No es muy golfista y actualmente no puede manejar múltiples términos (solo puede ejecutarlo varias veces, ¿verdad?), Pero puede manejar n^x, x^ny ncomo entrada.


Sin golf ...

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
Kyle Kanos
fuente
str.func(str,...)== str:func(...), por eso las cadenas obtuvieron la metatabla después de todo ...
mniip
@mniip: Todavía estoy aprendiendo Lua. Gracias por el consejo.
Kyle Kanos
1
Como el OP solo busca el código "que puede calcular en su cabeza", no me molestaría en definir una función y declarar llocal. Solo espere que la entrada se almacene ay diga que la salida se almacenará l.
Martin Ender
Puede omitir paréntesis a:find("x"), también tenga en cuenta que 1thensolo funciona en Lua 5.2
mniip
@mniip: Whoa, eso es genial, eso ()es opcional. El 1thenfue simplemente fija como no tengo 5.2 (no hacer las actualizaciones de CPU hasta después de la disertación es hecho b / c que no quiero estropear nada).
Kyle Kanos
3

ECMAScript 6, 127 bytes

Aquí está mi intento de expresión regular (usando una única expresión regular y algo de lógica en la devolución de llamada de reemplazo):

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

Esto espera que la cadena de entrada se almacene iy simplemente devuelve el resultado. Pruébelo en una consola compatible con ECMAScript 6 (como la de Firefox).

Martin Ender
fuente
2

sed, 110

Tomando muy literalmente "No es necesario simplificarlos ni formatearlos exactamente como se muestra arriba, siempre que esté claro lo que dice la respuesta":

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

El recuento de bytes incluye 1 para la rbandera.

Sin golf, con comentarios:

# 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

Ejecución de muestra:

$ 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

Apuesto a que esto podría jugar más golf; Es mi primer intento sed. ¡Divertido!

DLosc
fuente
1

Rubí, 152

... o 150 si no necesita imprimir ... o 147 si también está bien con una matriz que necesita unir.

corre 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}*''

sin golf:

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

Mi principal problema con este es el número de caracteres que toma la división adecuada. La única otra forma en que podía pensar era split(/(?<!\^)([-+])/)qué da +y -como sus propios resultados. ¿Alguna pista para una mejor solución?

Además, ¿hay una forma más corta de regresar ssi no está vacía, pero de lo contrario regresa y? He usado s[0]?y:s? En JS lo haría s||y, pero ""es verdad en Ruby.

No que Charles
fuente
¿Ayudaría una afirmación anticipada, así split(/(?<!\^)(?=[-+])/):?
DLosc