多項式のシンボリック微分


20

シンボリック識別1:ゴーン・シーフィッシン

仕事

stdin(1 <deg(p)<128)からxの多項式を取り込んで微分するプログラムを作成します。入力多項式は、次の形式の文字列になります。

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

各項の係数は整数です(-128 <a <128)。各用語は、1つのスペース、+、および別のスペースで区切られます。線形項と定数項は上記のように表示されます(つまり、no 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"

得点

スコアはプログラムのバイト単位の長さであり、組み込みまたはシンボリック代数を行うライブラリを使用する場合は3倍されます。


ここでこの課題にまだ取り組んでいないとは信じられません!
-flawr

5
@flawr やった。(ただし、他の機能も必要であり、出力形式に関する厳密な規則はありませんでした。)
Martin Ender

@flawr私は同じことを考えました...しかし、それでもマーティンのリンクされた投稿の検索は見つかりませんでした。まぁ。
hYPotenuser

回答:


15

網膜53 43 42 41 40 35バイト

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

カウントのために、各行は個別のファイルに入れられますが、-sフラグを使用してRetinaを呼び出すことで、上記を単一のファイルとして実行できます。

これは、入力文字列の数値が単項で与えられることを期待し、同じ形式で出力を生成します。例えば

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

説明

このコードでは、1つの正規表現の置換について説明しています。これは、基本的に4つの置換を1つに圧縮したものです。groupを埋めるのは1つのブランチのみである$2ため、他の3つのいずれかが一致すると、その一致は文字列から単に削除されることに注意してください。したがって、4つの異なるケースを別々に見ることができます。

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

に遭遇するxことなく文字列の先頭からスペースに到達できる場合、それは最初の用語が定数用語であり、それを削除することを意味します。の貪欲さのため+、これは定数項の後のプラスと2番目のスペースにも一致します。定数項がない場合、この部分は単純に一致しません。

x(?= )
<empty>

これxは、後に続くスペース、つまりx線形項(存在する場合)に一致し、それを削除します。多項式の次数は常に少なくとも2であるため、その後にスペースがあることを確認できます。

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

これにより、係数と指数の乗算が実行されます。これ1は、係数内の単一の要素と一致し、先読みを介して対応する指数全体で置き換えます。

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

これは、末尾1(先読みで保証)を一致させることにより、残りのすべての指数を削減します。一致する可能性がある場合^11(および単語の境界)、代わりにそれを削除し、線形項を正しく表示するようにします。

圧縮については、ほとんどの条件が相互に影響を与えないことがわかります。(\^1)?3番目のケースの先読みがtrueの場合は一致しないため、これら2つを次のようにまとめることができます。

(\^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に1つのバグを指摘し、2バイトをゴルフしてくれてありがとう!

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," + "))

これにより、文字列を受け入れて文字列を返すラムダ関数が作成されます。内部は、ジュリアコードが評価されるときに何が起こるかを模倣しています。文字列は、シンボル、式、および呼び出しに解析されます。実際に、Juliaの完全なシンボリック微分関数を作成して、Juliaの一部として送信することもできます。

Ungolfed +説明:

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さらに4回使用されます。主な迷惑なことは、文字列とintの間を行き来する必要があることですが、Python 2のバックティック演算子はそれを支援します。

次に、入力を用語に分割し、その中dにある各用語を呼び出して"x"、定数用語を削除します。結果は再び結合され、印刷されます。


2

CJam、62 57 55 49バイト

さて、デニスは、サイトがバックアップされたことに気付く前にこれを恥ずかしく思いました。しかし、とにかくここに私の作成があります:

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

最新バージョンでは、@ Dennisが提案するショートカットを使用して数バイトを節約します(変数を使用し、の代わりにスペースで分割します+)。

オンラインで試す


1
変数に保存することは、elseブロックにポップするよりも短くなります。たとえば、_({'^a\}{;}?は1バイトよりも長いです:T({T'^a\}&
デニス

1
プラス記号の代わりにスペースで分割する場合~、残りのelseブロックで必要はなく、そのブロックも削除できます。
デニス

@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

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

実際、主な悩みの種は、文字列と整数を変換する必要があることです。また、定数項が必要な場合、コードは153バイトのみになります。


最初の答えは、DLoscを破って撮影したことでした。
エレンディアスターマン

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

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

残念ながら、splitメソッドの名前を変更し、特定の関数で微分を実行するDLoscのトリックは、私のコードを短縮しません...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.