Символічна диференціація многочленів


20

Символічна диференціація 1: Пропав Коефішин

Завдання

Напишіть програму, яка приймає многочлен у x від stdin (1 <deg (p) <128) і диференціює її. Вхідним многочленом буде рядок наступної форми:

"a + bx + cx^2 + dx^3 +" ...

де коефіцієнт кожного члена є цілим числом (-128 <a <128). Кожен доданок відокремлений одним пробілом, а + та іншим простором; лінійні та постійні доданки відображаються як вище (тобто немає x^0або x^1). Умови з’являться в порядку збільшення ступеня, і ці повноваження з нульовим коефіцієнтом опущені. Усі терміни з коефіцієнтом 1 або -1 відображають цей коефіцієнт прямо.

Вихід повинен мати точно таку ж форму. Зауважте, що коефіцієнти на виході можуть бути такими ж, як 127 * 127 == 16129.

Приклади

"3 + 1x + 2x^2" ==> "1 + 4x"
"1 + 2x + -3x^2 + 17x^17 + -1x^107" ==> "2 + -6x + 289x^16 + -107x^106"
"17x + 1x^2" ==> "17 + 2x"

Оцінка балів

Ваш бал - це довжина вашої програми в байтах, помножена на три, якщо ви використовуєте вбудовану або бібліотеку, яка робить символічну алгебру.


Я не можу повірити, що у нас вже не було цього виклику!
flawr

5
@flawr Ми щось подібні. (Хоча для цього потрібні й інші функції та не було жорстких правил щодо формату виводу.)
Martin Ender,

@flawr Я думав те ж саме ... і все ж я не знайшов пов’язаний пост Мартіна в пошуку. Ну добре.
hYPotenuser

Відповіді:


15

Сітківка , 53 43 42 41 40 35 байт

^[^x]+ |(\^1)?\w(?=1*x.(1+)| |$)
$2

Для цілей підрахунку кожен рядок складається в окремому файлі, але ви можете запустити вищезазначене як єдиний файл, звернувшись до Retina із -sпрапором.

Це очікує, що числа у вхідному рядку будуть задані одинарними і дадуть вихід у тому ж форматі. Напр

1 + 11x + -111x^11 + 11x^111 + -1x^11111
-->
11 + -111111x + 111111x^11 + -11111x^1111

замість

1 + 2x + -3x^2 + 2x^3 + -1x^5
-->
2 + -6x + 6x^2 + -5x^4

Пояснення

Код описує одну заміну регулярного виразка, яка в основному становить 4 заміни, стиснуті в одну. Зауважте, що лише одна з гілок заповнить групу, $2тому якщо будь-яка з трьох інших збігів, відповідність буде просто видалена з рядка. Тож ми можемо розглядати чотири різні випадки окремо:

^[^x]+<space>
<empty>

Якщо можливо досягти пробілу з початку рядка, не зустрічаючи з тим, xщо означає, що перший член є постійним терміном, і ми його видаляємо. Через жадібність +, це також буде відповідати плюсу та другому пробілу після постійного терміну. Якщо немає постійного терміну, ця частина просто ніколи не збігатиметься.

x(?= )
<empty>

Це збігається з xінтервалом, за яким слідує пробіл, тобто xлінійний член (якщо він існує), і видаляє його. Ми можемо бути впевнені, що після нього є пробіл, оскільки ступінь многочлена завжди принаймні 2.

1(?=1*x.(1+))
$1

Це виконує множення коефіцієнта на показник. Це відповідає одиничному 1в коефіцієнті і замінює його на весь відповідний показник через lookahead.

(\^1)?1(?= |$)
<empty>

Це зменшує всі інші експоненти за рахунок узгодження задніх сторін 1(забезпечених lookahead). Якщо можливо збігнути ^11(і межу слова), ми видалимо це замість цього, що піклується про правильне відображення лінійного терміна.

Для стиснення ми помічаємо, що більшість умов не впливають один на одного. (\^1)?не буде відповідати, якщо пошук у третьому випадку є вірним, тому ми можемо скласти ці два як

(\^1)?1(?=1*x.(1+)| |$)
$2

Тепер у нас вже є пошук, необхідний для другого випадку, а інші ніколи не можуть бути правдивими при зіставленні x, тому ми можемо просто узагальнити 1до \w:

(\^1)?\w(?=1*x.(1+)| |$)
$2

Перший випадок насправді не має нічого спільного з іншими, тому ми тримаємо це окремо.


9

CJam, 43 41 байт

Qleu'^/';*'+/{~:E[*'x['^E(]]E<}/]1>" + "*

Дякуємо @ jimmy23013 за те, що він вказав на одну помилку та заграв у два байти!

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

Q           e# Leave an empty array on the bottom of the stack.
l           e# Read a line from STDIN.
eu'^/';*    e# Convert to uppercase and replace carets with semicolons.
'+/         e# Split at plus signs.

{           e# For each resulting chunk:
  ~         e#   Evaluate it. "X" pushes 1 and ";" discards.
            e#   For example, "3X" pushes (3 1) and "3X;2" (3 2).
   :E       e#   Save the rightmost integer (usually the exponent) in E.
   [        e#
     *      e#   Multiply both integers.
            e#   For a constant term c, this repeats the empty string (Q) c times.
     'x     e#   Push the character 'x'.
     ['^E(] e#   Push ['^' E-1].
   ]        e#
   E<       e#  Keep at most E elements of this array.
            e#  If E == 1, 'x' and ['^' E-1] are discarded.
            e#  If E == 2, ['^' E-1] is discarded.
            e#  If E >= 3, nothing is discarded.
}/          e#

]           e# Wrap the entire stack in an array.
1>          e# Discard its first element.
            e# If the first term was constant, this discards [""]. ["" 'x']
            e# or ["" 'x' ['^' E-1]], depending on the constant.
            e# In all other cases, it discards the untouched empty array (Q).
" + "*      e# Join all kept array elements, separating by " + ".

5

Perl, 64 63 байти

62b код + 1 командний рядок (-p)

Наразі не дивно, але я продовжую намагатися скоротити.

s/(\d+)x.(\d+)/$1*$2."x^".($2-1)/eg;s/\^1\b|^\d+ . |x(?!\^)//g

Приклад використання:

echo "1 + 2x + 3x^2" | perl -pe 's/(\d+)x.(\d+)/$1*$2."x^".($2-1)/eg;s/\^1\b|^\d+ . |x(?!\^)//g'

Дякую Денису за -1b


5

Джулія, 220 байт

Без регулярних виразів!

y->(A=Any[];for i=parse(y).args[2:end] T=typeof(i);T<:Int&&continue;T==Symbol?push!(A,1):(a=i.args;c=a[2];typeof(a[3])!=Expr?push!(A,c):(x=a[3].args[3];push!(A,string(c*x,"x",x>2?string("^",ex-1):""))))end;join(A," + "))

Це створює лямбда-функцію, яка приймає рядок і повертає рядок. Внутрішні зображення імітують те, що відбувається при оцінці коду Джулії: рядок розбирається на символи, вирази та виклики. Я, можливо, спробую написати повну функцію символічної диференціації Джулії та подати її як частину Джулії.

Недоліки + пояснення:

function polyderiv{T<:AbstractString}(y::T)

    # Start by parsing the string into an expression
    p = parse(y)

    # Define an output vector to hold each differentiated term
    A = Any[]

    # Loop through the elements of p, skipping the operand
    for i in p.args[2:end]

        T = typeof(i)

        # Each element will be an integer, symbol, or expression.
        # Integers are constants and thus integrate to 0. Symbols
        # represent x alone, i.e. "x" with no coefficient or
        # exponent, so they integrate to 1. The difficulty here
        # stems from parsing out the expressions.

        # Omit zero derivatives
        T <: Int && continue

        if T == Symbol
            # This term will integrate to 1
            push!(A, 1)
        else
            # Get the vector of parsed out expression components.
            # The first will be a symbol indicating the operand,
            # e.g. :+, :*, or :^. The second element is the
            # coefficient.
            a = i.args

            # Coefficient
            c = a[2]

            # If the third element is an expression, we have an
            # exponent, otherwise we simply have cx, where c is
            # the coefficient.
            if typeof(a[3]) != Expr
                push!(A, c)
            else
                # Exponent
                x = a[3].args[3]

                # String representation of the differentiated term
                s = string(c*x, "x", x > 2 ? string("^", x-1) : "")

                push!(A, s)
            end
        end
    end

    # Return the elements of A joined into a string
    join(A, " + ")
end

3

C, 204 162 байти

#define g getchar()^10
h,e;main(c){for(;!h&&scanf("%dx%n^%d",&c,&h,&e);h=g?g?e?printf(" + "):0,0:1:1)e=e?e:h?1:0,e?printf(e>2?"%dx^%d":e>1?"%dx":"%d",c*e,e-1):0;}

В основному проаналізуйте кожен термін і виведіть диференційований термін послідовно. Досить прямолінійний.


2

JavaScript ES6, 108 байт

f=s=>s.replace(/([-\d]+)(x)?\^?(\d+)?( \+ )?/g,(m,c,x,e,p)=>x?(c*e||c)+(--e?x+(e>1?'^'+e:''):'')+(p||''):'')

Фрагмент ES5:

// ES5 version, the only difference is no use of arrow functions.
function f(s) {
  return s.replace(/([-\d]+)(x)?\^?(\d+)?( \+ )?/g, function(m,c,x,e,p) {
    return x ? (c*e||c) + (--e?x+(e>1?'^'+e:''):'') + (p||'') : '';
  });
}

[
  '3 + 1x + 2x^2',
  '1 + 2x + -3x^2 + 17x^17 + -1x^107',
  '17x + 1x^2'
].forEach(function(preset) {
  var presetOption = new Option(preset, preset);
  presetSelect.appendChild(presetOption);
});

function loadPreset() {
  var value = presetSelect.value;
  polynomialInput.value = value;
  polynomialInput.disabled = !!value;
  showDifferential();
}

function showDifferential() {
  var value = polynomialInput.value;
  output.innerHTML = value ? f(value) : '';
}
code {
  display: block;
  margin: 1em 0;
}
<label for="presetSelect">Preset:</label>
<select id="presetSelect" onChange="loadPreset()">
  <option value="">None</option>
</select>
<input type="text" id="polynomialInput"/>
<button id="go" onclick="showDifferential()">Differentiate!</button>
<hr />
<code id="output">
</code>


2

Python 2, 166 байт

Хлопчик, це здається довше, ніж має бути.

S=str.split
def d(t):e="^"in t and int(S(t,"^")[1])-1;return`int(S(t,"x")[0])*(e+1)`+"x"[:e]+"^%d"%e*(e>1)
print" + ".join(d(t)for t in S(raw_input()," + ")if"x"in t)

Функція dприймає непостійний додаток tі повертає свою похідну. Причиною того, що я defфункцію замість використання лямбда, є те, що я можу призначити показник мінус 1 до e, який потім використовується ще чотири рази. Найголовніше дратує - це кидати вперед і назад між рядками та ints, хоча оператор backtick Python 2 допомагає в цьому.

Потім ми розділимо введення на терміни і зателефонуємо dдо кожного "x"з них, тим самим усуваючи постійний термін. Результати з'єднуються разом і друкуються.


2

CJam, 62 57 55 49 байт

Що ж, Денніс засумував це ще до того, як я навіть помітив, що сайт створив резервну копію. Але ось все-таки моє творіння:

lS/{'x/:T,({T~1>:T{~T~*'xT~(:T({'^T}&}&" + "}&}/;

Остання версія зберігає кілька байтів за допомогою ярликів, запропонованих @Dennis (використовуйте змінні та розділіть місце в просторі замість +).

Спробуйте в Інтернеті


1
Збереження в змінній коротше, ніж вискакування в іншому блоці. Наприклад, _({'^a\}{;}?на 1 байт довше, ніж :T({T'^a\}&.
Денніс

1
Якщо ви розділите на пробіли замість знаків плюс, вам не знадобиться ~інший блок, що залишився, і його також можна усунути.
Денніс

@Dennis Це працює, дякую. Спочатку я хотів усунути плюсові ознаки, але вони все одно випадають, коли я перевіряю на наявність x. Я знайшов ще кілька вдосконалень, поки я був на цьому. Переважно тому, що зараз у мене є значення змінних, я можу пригадати їх там, де вони мені справді потрібні, заощадивши деякі маніпуляції зі стеком. У мене також був зліт, aякий слід було б видалити, коли я оптимізував вихідну генерацію раніше.
Рето Коради

1

Pyth, 62 байти

jJ" + "m::j"x^",*Fdted"x.1$"\x"x.0"kftTmvMcd"x^"c:z"x ""x^1 "J

Досить потворне рішення, використовуючи деякі заміни геджекс.


1

Пітон 3, 176 байт

s=input().split(' + ')
y='x'in s[0]
L=map(lambda x:map(int,x.split('x^')),s[2-y:])
print(' + '.join([s[1-y][:-1]]+['x^'.join(map(str,[a*b,b-1])).rstrip('^1')for a,b in L]))

Дійсно, головне роздратування полягає в перетворенні між рядками та ints. Крім того, якщо потрібен був постійний термін, код становитиме лише 153 байти.


Перша відповідь, стрілянина за побиття DLosc, не зовсім туди потрапила.
El'endia Starman

0

Python 2, 229 байт

import os
print' + '.join([i,i[:-2]][i[-2:]=='^1'].replace('x^0','')for i in[`a*b`+'x^'+`b-1`for a,b in[map(int,a.split('x^'))for a in[[[i+'x^0',i+'^1'][i[-1]=='x'],i]['^'in i]for i in os.read(0,9**9).split(' + ')]]]if i[0]!='0')

0

Пітон 2, 174 байти

print' + '.join(['%d%s%s'%(b[0]*b[1],'x'*(b[1]>1),'^%d'%(b[1]-1)*(b[1]>2))for b in[map(int,a.split('x^')if 'x^'in a else[a[:-1],1])for a in input().split(' + ')if 'x'in a]])

На жаль, хитрість DLosc перейменувати метод розділення та виконати диференціацію в певній функції не скорочує мій код ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.