Bantu saya dengan kalkulus diferensial!

52

Saya suka pemrograman dan tahu setiap bahasa, tapi saya payah dalam matematika. Sayangnya, sekolah saya mengharuskan siswa komputer harus mengambil satu tahun kalkulus. Ada tes minggu depan, dan saya tidak tahu rumus apa pun untuk turunan!

Tolong bantu saya menemukan formula. Saya memerlukan lembar contekan - program (sesingkat mungkin sehingga guru saya tidak akan melihatnya) yang mengambil ekspresi (seperti 4*x^3-2) sebagai input dan output turunannya. (Saya tidak peduli apakah input dan output menggunakan argumen baris perintah, STDIN, STDOUT, atau apa pun, karena saya tetap melakukan semua perhitungan di kepala saya.)

Tes ini mencakup beberapa jenis fungsi berikut:

  • Konstanta, suka -3atau8.5
  • Fungsi daya, seperti x^0.5ataux^-7
  • Fungsi eksponensial, suka 0.5^xatau 7^x(basis selalu positif)
  • Konstanta dikalikan dengan fungsi, seperti 3*x^5atau-0.1*0.3^x
  • Jumlah dan perbedaan beberapa fungsi, seperti -5*x^2+10-3^x

Guru saya selalu memformat pertanyaannya dengan cara yang persis sama, seperti yang ditunjukkan di atas. Dia juga tidak menggunakan pecahan, angka seperti pi atau e , atau angka yang sangat besar (lebih dari 1.000). Dia tidak pernah menggunakan tanda kurung, dan selalu menunjukkan multiplikasi menggunakan tanda bintang ( *). Satu-satunya variabel yang digunakan adalah selalu x .

Di sisi lain, guru saya cukup toleran terhadap jawaban. Mereka tidak perlu disederhanakan sama sekali atau diformat persis seperti yang ditunjukkan di atas, selama jelas apa yang dikatakan jawabannya.

Meskipun saya dapat menggunakan bahasa apa pun, ingatlah bahwa saya tidak dapat menemukan turunan sendiri. Jadi jika program menggunakan fungsi bawaan untuk menangani persamaan atau menghitung turunan, saya tidak akan bisa menggunakannya.

Selama pengujian, saya tidak akan memiliki akses ke Internet atau file apa pun selain program pada lembar contekan.

Catatan: Skenario ini sepenuhnya fiksi. Dalam kehidupan nyata, menipu dan membantu orang lain menipu adalah salah dan tidak boleh dilakukan.

Ypnypn
sumber
3
Bisakah kita berharap bahwa xselalu variabel untuk membedakan?
Kyle Kanos
2
Haruskah jawabannya disederhanakan? Apakah kita perlu menambahkan istilah serupa?
Rainbolt
1
Saya kira sudah waktunya untuk proyek kalkulus saya di scrblnrd3.github.io/Javascript-CAS untuk bersinar jika saya benar-benar bisa golf itu
scrblnrd3
1
Haruskah kita berasumsi tidak ada orangtua?
Bukan karena Charles
2
Saya telah menjawab sebagian besar pertanyaan ini dalam hasil edit saya . Tidak ada notasi ilmiah atau aturan produk.
Ypnypn

Jawaban:

8

Wolfram 136 134 109 [Terima kasih kepada Calle atas komentarnya di bawah ini]

Dukungan terbatas untuk aturan produk dan rantai.

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}

Contoh:

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]

Perhatikan bahwa ini tidak menggunakan "fungsi bawaan untuk berurusan dengan persamaan atau menghitung turunan": hanya pencocokan pola yang terlibat *.

[* Yah ... secara teknis interpreter juga mem-parsing dan membangun semacam AST dari input juga]


Tidak Disatukan:

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
sumber
Ini adalah versi lain . Anda tidak harus menulis Power, Timesdll. Tentukan berapa banyak yang akan meningkatkan versi golf Anda, tetapi Anda memiliki setidaknya satu Timesdi sana sehingga Anda dapat def. simpan beberapa karakter. Perhatikan juga bahwa dalam versi Anda yang tidak disunat disebutkan d[expr_]:= v/....
1
@Calle "IDK berapa banyak yang akan meningkatkan versi golf Anda" - 25 byte! Tepuk tangan!
Saran
26

Perl - 121 122

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

Uji:

$ 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
sumber
Namun alasan lain bagi saya untuk belajar regex ...
Kyle Kanos
3
@KyleKanos Jangan. Regex itu buruk, regex itu hebat.
mniip
Meh, pukuli aku untuk itu. Tidak buruk! (PS: regex itu indah)
Martin Ender
8
Saya tidak tahu apa yang terjadi di sini. +1
qwr
4
Penjelasan: Konstan -> 0, x -> 1, x ^ n -> n * x ^ (n-1), a ^ x -> ln (a) * a ^ x
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
7

Haskell 38 Chars

Fungsi tersebut dmengambil fungsi dan mengembalikan fungsi. Dimasukkan dalam bentuk seri daya , dan dihasilkan dengan cara yang sama (yang merupakan jenis apa pun.)

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

Misalnya, jika kita input x->x^2, kita dapatkan x->2*x.

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

Dan untuk fungsi eksponensial.

λ <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
sumber
5
Tapi OP tidak tahu matematika apa pun! Bisakah kita mengharapkan dia untuk mengekspresikan input eksponensial sebagai seri kekuatan?
Saran
Yah dia jelas tahu notasi. Dia hanya tidak tahu bagaimana melakukan operasi turunan.
PyRulez
5
Bisakah ini menangani 2^x?
Kyle Kanos
5
Sihir apakah ini?
Christofer Ohlsson
7
Saya tidak melihat di mana "mengambil ekspresi (seperti 4*x^3-2) sebagai input", seperti yang disyaratkan oleh 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).

Operator yang didukung: biner +, biner -, biner *, biner ^, unary -. Perhatikan bahwa unary +tidak didukung.

Contoh dijalankan:

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 bingung ketika berjalan ke dalam ^-urutan. Sebuah spasi harus dimasukkan di antara ^dan -untuk mem-parsing ekspresi dengan benar.

Semoga guru Anda tidak keberatan dengan persamaan.

Waktu gila:

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̷̰̀ĥ̷̳
sumber
4

C, 260

Hei, kurasa aku tahu gurumu! Bukankah itu orang yang memiliki kemampuan supranatural untuk mendeteksi siswa yang menjalankan fungsi pencocokan pola perpustakaan di kepala mereka?

Jadi, menggunakan sscanfitu tidak mungkin ... Tapi jangan khawatir:

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

Menjalankan contoh (input aktif stdin; output ke stdout):

4 * x ^ 3-2

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

Format ini jauh lebih baik dari sekadar 12*x^2, karena dengan cara ini guru Anda dapat memastikan bahwa Anda menghitung sendiri jawabannya dan tidak menipu dengan menyalinnya dari orang lain!

x + 2 ^ x

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

Keluaran memiliki sedikit masalah domain x=0, tetapi hampir benar di mana-mana !

Sebagai referensi, ini adalah versi yang tidak dikolonisasi, dapat dibaca (oleh manusia biasa). Menggunakan mesin negara dengan 5 negara dan 5 kategori karakter 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 Hati-hati dengan getsfungsi itu: ia memiliki kerentanan keamanan yang dapat membuat guru Anda menjalankan rootkit di pikiran Anda dengan memberikan input terlalu lama ...

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

Tidak terlalu bermain golf dan saat ini tidak dapat menangani beberapa istilah (Anda bisa menjalankannya beberapa kali, bukan?), Tetapi dapat menangani n^x, x^ndan nsebagai input.


Tidak disatukan ...

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
sumber
str.func(str,...)== str:func(...), itu sebabnya string mendapatkan metatable setelah semua ...
mniip
@mniip: Masih belajar Lua. Terima kasih atas tipnya.
Kyle Kanos
1
Karena OP hanya mencari kode "dia bisa menghitung di kepalanya", saya tidak akan repot mendefinisikan fungsi dan mendeklarasikan llokal. Hanya berharap input untuk disimpan adan katakan output akan disimpan l.
Martin Ender
Anda dapat menghilangkan tanda kurung di dalam a:find("x"), juga perhatikan bahwa 1thenhanya berfungsi di Lua 5.2
mniip
@ mniip: Wah, keren sekali itu ()opsional. Itu 1thenhanya diperbaiki karena saya tidak memiliki 5,2 (tidak melakukan pembaruan CPU sampai setelah disertasi selesai b / c saya tidak ingin mengacaukan sesuatu).
Kyle Kanos
3

ECMAScript 6, 127 byte

Berikut ini adalah upaya regex saya (menggunakan regex tunggal dan beberapa logika dalam callback pengganti):

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

Ini mengharapkan string input untuk disimpan idan hanya mengembalikan hasilnya. Cobalah di konsol yang sesuai ECMAScript 6 (seperti Firefox).

Martin Ender
sumber
2

sed, 110

Mengambil sangat harfiah "Mereka tidak perlu disederhanakan sama sekali atau diformat persis seperti yang ditunjukkan di atas, selama jelas apa yang dikatakan jawabannya":

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

Jumlah byte termasuk 1 untuk rflag.

Tidak disatukan, dengan komentar:

# 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

Contoh dijalankan:

$ 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

Saya bertaruh ini bisa di-golf lebih lanjut; ini percobaan pertama saya sed. Menyenangkan!

DLosc
sumber
1

Ruby, 152

... atau 150 jika Anda tidak perlu mencetak ... atau 147 jika Anda juga tidak masalah dengan array yang Anda butuhkan untuk bergabung sendiri.

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

Masalah utama saya dengan yang satu ini adalah jumlah karakter yang diperlukan pemisahan. Satu-satunya cara lain yang bisa saya pikirkan adalah split(/(?<!\^)([-+])/)memberi +dan -sebagai hasil mereka sendiri. Adakah petunjuk untuk solusi yang lebih baik?

Juga, apakah ada cara yang lebih singkat untuk kembali sjika tidak kosong, tetapi sebaliknya kembali y? Saya sudah menggunakan s[0]?y:s? Di JS saya baru saja melakukannya s||y, tetapi ""jujur ​​di Ruby.

Bukan itu Charles
sumber
Akan LookAhead pernyataan bantuan, seperti: split(/(?<!\^)(?=[-+])/)?
DLosc