ความแตกต่างเชิงสัญลักษณ์ของพหุนาม


20

ความแตกต่างเชิงสัญลักษณ์ 1: Gone Coefishin '

งาน

เขียนโปรแกรมที่ใช้พหุนามใน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"

เกณฑ์การให้คะแนน

คะแนนของคุณคือความยาวของโปรแกรมเป็นไบต์คูณด้วยสามถ้าคุณใช้บิวด์อินหรือไลบรารีที่ใช้พีชคณิตเชิงสัญลักษณ์


ฉันไม่อยากจะเชื่อเลยว่าเรายังไม่มีความท้าทายนี้ที่นี่!
ข้อบกพร่อง

5
@ flawr เราจัดเรียงของได้ (แม้ว่าจำเป็นต้องใช้ฟังก์ชั่นอื่น ๆ เช่นกันและไม่มีกฎที่เข้มงวดในรูปแบบเอาต์พุต)
Martin Ender

@flawr ฉันคิดเหมือนกัน ... แต่ฉันยังไม่พบการค้นหาโพสต์ที่เชื่อมโยงของ Martin อ่า
hYPotenuser

คำตอบ:


15

เรติน่า , 53 43 42 41 40 35 ไบต์

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

สำหรับวัตถุประสงค์ในการนับแต่ละบรรทัดจะเป็นไฟล์แยกต่างหาก แต่คุณสามารถเรียกใช้ไฟล์ข้างต้นเป็นไฟล์เดียวได้โดยเรียกใช้ Retina ด้วยการ-sตั้งค่าสถานะ

สิ่งนี้คาดว่าตัวเลขในสตริงอินพุตจะถูกกำหนดเป็น unaryและจะให้ผลลัพธ์ในรูปแบบเดียวกัน เช่น

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

คำอธิบาย

รหัสอธิบายการทดแทน regex เดียวซึ่งโดยทั่วไปจะมีการทดแทน 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)?จะไม่ตรงกันถ้า lookahead ในกรณีที่สามเป็นจริงดังนั้นเราจึงสามารถรวมสองสิ่งนี้เข้าด้วยกันเป็น

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

ตอนนี้เรามี lookahead ที่จำเป็นสำหรับกรณีที่สองและสิ่งอื่น ๆ ไม่สามารถเป็นจริงได้เมื่อทำการจับคู่xดังนั้นเราจึงสามารถสรุป1ให้ a \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

เพิร์ล 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'

ขอบคุณ Denis สำหรับ -1b


5

Julia, 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: สตริงจะถูกวิเคราะห์เป็นสัญลักษณ์การแสดงออกและการโทร ฉันอาจลองเขียนฟังก์ชั่นสร้างความแตกต่างเชิงสัญลักษณ์จูเลียและส่งมันให้เป็นส่วนหนึ่งของจูเลีย

คำอธิบาย 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ได้ซึ่งจะถูกใช้อีกสี่ครั้ง สิ่งที่น่ารำคาญที่สำคัญคือต้องย้อนกลับไปมาระหว่างสายและ ints ถึงแม้ว่าตัวดำเนินการ backtick ของ Python 2 จะช่วยในเรื่องนั้น

จากนั้นเราแบ่งอินพุตเป็นเทอมและโทรหาdแต่ละอันที่มี"x"อยู่ในนั้นเพื่อกำจัดเทอมคงที่ ผลลัพธ์จะถูกรวมเข้าด้วยกันและพิมพ์ออกมา


2

CJam, 62 57 55 49 ไบต์

เดนนิสทำให้เรื่องนี้น่าละอายก่อนที่ฉันจะสังเกตเห็นว่าเว็บไซต์กลับมา แต่นี่คือการสร้างของฉันต่อไป:

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

เวอร์ชันล่าสุดบันทึกไม่กี่ไบต์ด้วยทางลัดที่ @Dennis แนะนำ (ใช้ตัวแปรและแยกที่เว้นวรรคแทน+)

ลองออนไลน์


1
การบันทึกในตัวแปรสั้นกว่าการ popping ในบล็อกอื่น ยกตัวอย่างเช่น_({'^a\}{;}?เป็น 1 :T({T'^a\}&ไบต์นานกว่า
เดนนิส

1
หากคุณแยกที่ช่องว่างแทนเครื่องหมายบวกคุณไม่จำเป็นต้อง~บล็อกส่วนที่เหลือและสามารถกำจัดอันนั้นได้เช่นกัน
เดนนิส

@Dennis นั่นได้ผลขอบคุณ ผมอยากที่จะกำจัดบวก xแต่พวกเขาเลื่อนออกอยู่แล้วเมื่อฉันทดสอบสำหรับการปรากฏตัวของ ฉันพบการปรับปรุงเพิ่มเติมในขณะที่ฉันอยู่ที่นี่ ส่วนใหญ่เป็นเพราะฉันมีค่าในตัวแปรตอนนี้ฉันสามารถจำพวกเขาในที่ที่ฉันต้องการพวกเขาจริงๆบันทึกการจัดการกองซ้อน ฉันยังมีหลงทางaที่ควรถูกลบเมื่อฉันปรับการสร้างผลลัพธ์ก่อนหน้านี้
Reto Koradi

1

Pyth, 62 ไบต์

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

วิธีแก้ปัญหาที่ค่อนข้างน่าเกลียดโดยใช้การทดแทน regex


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

อันที่จริงความรำคาญหลักคือต้องแปลงระหว่างสตริงและ 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

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

น่าเสียดายที่เคล็ดลับของ DLosc ในการเปลี่ยนชื่อวิธีการแยกและทำการแยกความแตกต่างในฟังก์ชั่นที่ระบุไม่ทำให้รหัสของฉันสั้นลง ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.