Допоможіть мені з диференціальним обчисленням!


52

Я люблю програмування і знаю кожну мову, але я засідаю з математики. На жаль, моя школа вимагає, щоб учні з комп’ютерів повинні пройти рік обчислення. Наступний тиждень є тест, і я не знаю жодної з формул похідних!

Будь ласка, допоможіть мені знайти формули. Мені потрібен шпаргалка - програма (якомога коротша, щоб мій вчитель не помічала цього), яка приймає вираження (як 4*x^3-2) у якості введення та виводить похідну. (Мені байдуже, чи використовуються вхідні та вихідні аргументи командного рядка, STDIN, STDOUT чи будь-що інше, оскільки я все-таки роблю всі обчислення в голові.)

Тест охоплює такі типи функцій:

  • Константи, як -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

Мій вчитель завжди формулює свої запитання точно так само, як показано вище. Він також не використовує жодних дробів, чисел, таких як pi чи e , або дійсно великих чисел (більше 1000). Він ніколи не використовує дужки та завжди показує множення за допомогою зірочки ( *). Єдина використовувана змінна завжди - x .

З іншого боку, мій вчитель досить поблажливий до відповідей. Їх взагалі не потрібно спрощувати або форматувати саме так, як показано вище, доки зрозуміло, що йдеться у відповіді.

Хоча я можу використовувати будь-яку мову, пам’ятайте, що я не можу самостійно з'ясувати похідні. Отже, якщо програма використовує вбудовані функції для обробки рівнянь або обчислення похідних, я не зможу її використовувати.

Під час тесту я не матиму доступу до Інтернету чи будь-яких файлів, окрім програми, на шпаргалці.

Примітка. Цей сценарій повністю вигаданий. У реальному житті обман і допомога іншим обманювати неправильно і ніколи цього не слід робити.


3
Чи можемо ми очікувати, що xце завжди може відрізнятись змінна?
Кайл Канос

2
Чи повинна відповідь бути спрощеною? Чи потрібно нам додавати такі терміни?
Rainbolt

1
Я здогадуюсь, настав час для мого проекту обчислення на scrblnrd3.github.io/Javascript-CAS, щоб засвітити, чи зможу я його справді
гольфувати

1
Чи слід вважати, що немає паронів?
Не те, що Чарльз

2
Я відповів на більшість цих питань у своїй редакції . Не існує наукових позначень чи правил про товар.
Ypnypn

Відповіді:


8

Wolfram 136 134 109 [Дякую Калле за коментар нижче]

Обмежена підтримка правил продукту та ланцюга.

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}

Приклад:

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]

Зауважте, що це не використовує жодних "вбудованих функцій для роботи з рівняннями або обчислення похідних": бере участь лише відповідність шаблонів *.

[* Ну ... технічно інтерпретатор також аналізує і створює свого роду AST також із вхідних даних]


Безголівки:

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
}

Це ще одна версія . Вам не доведеться писати Powerі Timesт. Д. ІДК, наскільки це поліпшить вашу версію для гольфу, але у вас є хоча б одна, Timesщоб ви могли визначитися. зберегти деякі символи. Також зауважте, що у вашій невольфізованій версії написано d[expr_]:= v/....

1
@Calle "IDK наскільки це покращить вашу версію для гольфу" - 25 байт! Ура!
Саран

26

Perl - 121 122

(+2 для -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

Тест:

$ 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

Ще одна причина для мене навчитися
регексу

3
@KyleKanos Не варто. Регекс поганий, регекс - приголомшливий.
mniip

Мех, побив мене до цього. Непогано! (PS: регекс прекрасний)
Мартін Ендер

8
Я поняття не маю, що тут відбувається. +1
qwr

4
Пояснення: Константа -> 0, x -> 1, x ^ n -> n * x ^ (n-1), a ^ x -> ln (a) * a ^ x
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

7

Haskell 38 Chars

Функція dбере функцію і повертає функцію. Він вводиться у вигляді силового ряду і виводиться так само (що є типом будь-якого.)

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

Наприклад, якщо ми вводимо x->x^2, ми отримуємо x->2*x.

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

І для експоненціальної функції.

λ <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
Але ОП не знає математики! Чи можемо ми очікувати, що він викладе свій експоненціальний внесок як енергетичний ряд?
Саран

Ну він, очевидно, знає нотацію. Він просто не знає, як зробити похідну операцію.
PyRulez

5
Чи може це впоратися 2^x?
Кайл Канос

5
Що це за чаклунство?
Крістофер Олссон

7
Я не бачу, звідки він "приймає вираз (як 4*x^3-2) як вхід", як цього вимагає ОП.
Гейб

5

Пролог 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).

Підтримувані оператори: двійкові +, двійкові -, двійкові *, двійкові ^, одинарні -. Зауважте, що унар +не підтримується.

Вибірка зразка:

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

Пролог плутається, коли він працює в ^-послідовності. Простір має бути вставлено між ^і -для того , щоб правильно розібрати вираз.

Сподіваємось, ваш вчитель не проти безладу рівнянь.

Божевільний час:

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

С, 260

Гей, я думаю, я знаю твого вчителя! Хіба не той, хто має надприродну здатність виявляти учнів, що виконують функції бібліотеки, що відповідають малюнкам, у голові?

Тож використання не sscanfвикликає сумнівів ... Але не хвилюйтеся:

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

Приклади запуску (вхід включено stdin; вихід йде в stdout):

4 * х ^ 3-2

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

Цей формат набагато кращий, ніж просто 12*x^2, адже таким чином ваш вчитель може бути впевнений, що ви самі розрахували відповідь і не обдурили, скопіювавши її у когось іншого!

х + 2 ^ х

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

Вихід має незначну проблему з доменом x=0, але це практично практично скрізь !

Для довідки, ось версія, яка не читається, просто читається (простими смертними). Він використовує машину стану з 5 станами та 5 категоріями вхідних символів.

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 Слідкуйте за цією getsфункцією: вона має вразливу безпеку, яка може дозволити вашому вчителю виконувати руткіт у вашій свідомості, надаючи занадто довгий вклад ...


3

Луа 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

Не дуже golfed і не може в даний час обробляти кілька термінів (ви можете просто запустити його кілька разів, НЕ так?), Але він може працювати n^x, x^nі в nякості вхідних даних.


Необурені ...

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(...), тому рядки отримали метаболію зрештою ...
mniip

@mniip: Ще вивчаю Луа. Дякую за пораду.
Кайл Канос

1
Оскільки ОП шукає лише код "він може обчислити в голові", я б не переймався визначенням функції та оголошенням lлокального. Просто очікуйте, що вхід буде збережений, aі скажіть, що вихід буде зберігатися в l.
Мартін Ендер

Ви можете пропустити круглі дужки a:find("x"), також зауважте, що 1thenпрацює лише в Lua 5.2
mniip

@mniip: О, це дуже круто, що ()необов’язково. Це 1thenбуло просто зафіксовано, оскільки у мене немає 5.2 (не роблю жодних оновлень процесора, поки після дисертації не буде зроблено b / c, я не хочу нічого зіпсувати).
Кайл Канос

3

ECMAScript 6, 127 байт

Ось моя спроба регулярного вибору (з використанням одного регулярного вираження та деякої логіки у зворотному заміні зворотного виклику):

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

Це очікує, що вхідний рядок буде збережено в iі просто поверне результат. Спробуйте це на консолі, сумісній із ECMAScript 6 (як у Firefox).


2

sed, 110

Беручи дуже буквально "Їх не потрібно спрощувати взагалі або форматувати саме так, як показано вище, до тих пір, поки зрозуміло, про що йдеться у відповідь":

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

Кількість байтів включає 1 для rпрапора.

Безголовка, з коментарями:

# 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

Вибірка зразка:

$ 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

Б'юсь об заклад, що це може бути ще гольф; це моя перша спроба sed. Весело!


1

Рубі, 152

... або 150, якщо вам не потрібно друкувати ... або 147, якщо ви також добре з масивом, який вам потрібно приєднати.

бігати з 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}*''

неозорений:

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

Моя головна проблема з цим - кількість символів, які займає правильне розщеплення. Єдиний інший спосіб, який я міг придумати, - це те, split(/(?<!\^)([-+])/)що дає +і -як власні результати. Будь-які натяки на краще рішення?

Також, чи є коротший спосіб повернення, sякщо він не порожній, але в іншому випадку повертається y? Я використовував s[0]?y:s? У JS я би просто зробив s||y, але ""це руті в Рубі.


Чи могло б допомогти твердження lookahead, як так split(/(?<!\^)(?=[-+])/):?
DLosc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.