Nội suy đa thức


12

Viết chương trình thực hiện Nội suy đa thức bằng các số hữu tỷ chính xác tùy ý. Đầu vào trông như thế này:

f (1) = 2/3
f (2) = 4/5
f (3) = 6/7
...

Bạn có thể giả sử rằng có chính xác một khoảng trắng trước và sau =dấu, tất cả các số là phân số hoặc số nguyên. Bạn cũng có thể giả định rằng tất cả các phần trong đầu vào đã không thể giảm được.

Không cần kiểm tra lỗi, bạn có thể cho rằng đầu vào là hợp lệ và không có x được nhân đôi trong f (x).

Đầu ra phải ở dạng tương thích LaTeX, mã LaTeX được phát ra sẽ mang lại biểu diễn đồ họa giống như đầu ra được đưa ra ở đây.

f (x) = 123x ^ 2 + \ frac {45} {2} x + \ frac {7} {4}

Phân số phải được giảm càng nhiều càng tốt, ví dụ. một cái gì đó như \frac{2}{4} không được phép. Nếu số là số nguyên, không sử dụng phân số.

Quy tắc đặc biệt:

Chương trình của bạn nên ...

  • làm việc cho đa thức đến cấp 12
  • hoàn thành trong ít hơn 1 phút cho đầu vào hợp lý
  • không sử dụng bất kỳ hàm nào thực hiện toàn bộ tính toán cho bạn
  • đầu ra đa thức bậc nhỏ nhất có thể

Testcase:

Các thử nghiệm nhất định chỉ là để làm rõ. Chương trình của bạn sẽ mang lại kết quả chính xác cho tất cả các đầu vào chính xác.

Đầu vào

f (1) = 2/3
f (2) = 4/5
f (3) = 6/7

Đầu ra

f (x) = - \ frac {4} {105} x ^ 2
       + \ frac {26} {105} x
       + \ frac {16} {35}

Đầu vào

f (-12) = 13/2
f (5/3) = 3/5
f (13) = -6
f (1/5) = -3/4

Đầu ra

f (x) = - \ frac {2186133} {239455744} x ^ 3
       + \ frac {2741731} {149659840} x ^ 2
       + \ frac {26720517} {29201920} x
       - \ frac {279464297} {299319680}

Đầu vào

f (4/3) = 617/81
f (2) = 20/3
f (-8/3) = 6749/81
f (-5) = 7367/12
f (0) = 23/3

Đầu ra

f (x) = \ frac {1} {2} x ^ 4
     - 2 ^ 3
     + \ frac {7} {4} x ^ 2
     + \ frac {23} {3}

Đầu vào

f (0) = 5
f (1) = 7
f (2) = 9
f (3) = 11
f (4) = 13

Đầu ra

f (x) = 2 lần
     + 5

Đầu vào

f (1/2) = -1/2
f (-25) = -1/2
f (-54/12) = -1/2

Đầu ra

f (x) = - \ frac {1} {2}

Tại sao bạn nói về số thực nếu tất cả những gì bạn từng sử dụng là số hữu tỷ?
Joey

Lấy làm tiếc. Tiếng Anh của tôi thì tệ. Có, chỉ sử dụng số hữu tỷ. Kết quả phải chính xác.
FUZxxl

Trong thử nghiệm đầu tiên, dấu chấm ( ...) có thực sự là một phần của đầu vào không?
Eelvex

@Eelvex: Không. Đã sửa.
FUZxxl

Đầu ra cho testcase thứ ba là sai. Câu trả lời đúng là -\frac{37745}{14592}x^4 - \frac{853249}{43776}x^3 + \frac{57809}{7296}x^2 + \frac{225205}{2736}x + \frac{23}{3}. Tôi nghi ngờ đầu vào được dự định là một cái gì đó khác nhau :)
Timwi

Câu trả lời:


3

J + sh

Kịch bản J:

i=:0".(1!:1)3
i=:((-:#i),2)$i
c=:|.(%.(x:((i.#i)^~])"0({."1 i)))(+/ .*)(|:{:"1 i)
(":(-.0=c)#(c,.i.-#c))(1!:2)2

kịch bản sh:

echo -n 'f(x) = '
tr -d 'f()=' | tr /\\n- r' '_  | ./polyint.ijs | sed -e 's/^/+/;s/_/-/;s/\([0-9]*\)r\([0-9]*\)/\\frac{\1}{\2}/;s/ \([0-9]*$\)/x^\1/;s/\^1//;s/x^0//;s/+\(.*-.*\)/\1/'

Chạy tập lệnh sh:

./pol-int.sh
f(1/2) = -1/2
f(-25) = -1/2
f(-54/12) = -1/2

f(x) = -\frac{1}{2}

.

./pol-int.sh
f(4/3) = 617/8
f(2) = 20/3
f(-8/3) = 6749/81
f(-5) = 7367/12
f(0) = 23/3

f(x) = -\frac{37745}{14592}x^4
       -\frac{853249}{43776}x^3
     +  \frac{57809}{7296}x^2
     + \frac{225205}{2736}x
     +  \frac{23}{3}

Bạn không phải tạo định dạng mã chính xác giống nhau. Trong đầu ra LaTeX. Nó sẽ chỉ mang lại biểu diễn đồ họa tương tự sau khi chạy qua LaTeX. Hãy tiết kiệm một số ký tự.
FUZxxl

Tôi không thể đọc J, nhưng từ độ dài ngắn tôi có nghĩa là J có chức năng tích hợp sẵn cho dạng phản hồi ma trận?
Timwi

@Timwi: Không, nhưng tôi sử dụng "ma trận nghịch đảo" tích hợp. Mặc dù vậy, J rất ngắn gọn: ngay cả khi tôi thực hiện "ma trận đảo ngược" thì nó cũng sẽ dài vài ký tự.
Eelvex

3

Perl (569 ký tự)

use Math'BigInt;sub r{($u,$v)=@_;$v?r($v,$u%$v):$u}sub c{new Math'BigInt$_[0]}$a=@c=<>;for(@c){m!(-?\d+)/?(\d*). = (-?\d+)/?(\d*)!;$j{$_,$i}=$1**c$_,$k{$_,$i|=0}=($2||1)**c$_ for 0..$a;$j{$a,$i}=c$3;$k{$a,$i++}=c$4||1}for$p(0..$a-1){for$y(0..$p-1,$p+1..$a-1){$n=$j{$p,$y}*$k{$p,$p};$o=$k{$p,$y}*$j{$p,$p};$j{$_,$y}=$j{$_,$y}*$k{$_,$p}*$o-$k{$_,$y}*$j{$_,$p}*$n,$k{$_,$y}*=$k{$_,$p}*$o for 0..$a}}print"f(x)=";for(1..$a){$s=r$t=$j{$a,$p=$a-$_}*$k{$p,$p},$w=$k{$a,$p}*$j{$p,$p};$u=abs$t,print$t>0?"$z":'-',($z='+',$w/=$s)-1?"\\frac{$u}{$w}":$u,$p>1?"x^$p":x x$p if$t/=$s}

Giải thích chi tiết:

use Math'BigInt;

# Subroutine to calculate gcd of two numbers
sub r{($u,$v)=@_;$v?r($v,$u%$v):$u}

# Subroutine to create BigInts
sub c{new Math'BigInt$_[0]}

# Read input
# Throughout, $a is the number of equations.
$a=@c=<>;

# Initialises the $a+1 × $a matrix with all the values.
# $j{$x,$y} contains the numerator, $k{$x,$y} the denominator.
for(@c)
{
    m!(-?\d+)/?(\d*). = (-?\d+)/?(\d*)!;

    # Puzzle for the reader: why is $i|=0 in the second one,
    # not the first one? Answer at the bottom!
    $j{$_,$i}=$1**c$_,$k{$_,$i|=0}=($2||1)**c$_ for 0..$a;
    $j{$a,$i}=c$3;
    $k{$a,$i++}=c$4||1
}

# Generates the matrix echelon form.
# Basically, it works like this:
for$p(0..$a-1)
{
    # For each element along the diagonal {$p,$p}, set all the values above and
    # below it to 0 by adding a multiple of row $p to each of the other rows.
    for$y(0..$p-1,$p+1..$a-1)
    {
        # So we need to multiply the row $p by the value of {$p,$y}/{$p,$p}
        # (stored in $n/$o) and then subtract that from row $y.
        $n=$j{$p,$y}*$k{$p,$p};
        $o=$k{$p,$y}*$j{$p,$p};
            $j{$_,$y}=$j{$_,$y}*$k{$_,$p}*$o-$k{$_,$y}*$j{$_,$p}*$n,
            $k{$_,$y}*=$k{$_,$p}*$o
        for 0..$a
    }
}

# Outputs the result
print"f(x)=";
for(1..$a)
{
    # Note this sets $p = $a-$_. $p is the power of x.
    # We need to divide {$a,$p} by {$p,$p}. Store the result in $t/$w.
    # We also need to put the fraction in lowest terms, so calculate the gcd.
    $s=r$t=$j{$a,$p=$a-$_}*$k{$p,$p},$w=$k{$a,$p}*$j{$p,$p};

    # Output this term only if the numerator ($t) is non-zero.
    # Output a plus sign only if this isn’t the first term.
    # Output a fraction only if the denomator ($w) isn’t 1.
        $u=abs$t,print$t>0?"$z":'-',
        ($z='+',$w/=$s)-1?"\\frac{$u}{$w}":$u,$p>1?"x^$p":x x$p
    if$t/=$s
}

# Answer to the puzzle buried in the code above:
# It’s because the second part is passed as a second argument to c,
# hence it is evaluated before the first part.

Bình luận

  • Tôi chắc chắn có một mô-đun để thao tác ma trận cung cấp một hàm cho dạng vang. Tôi đặc biệt không sử dụng cái đó (thậm chí không tìm kiếm cái nào) vì tôi cho rằng đây là điểm chính của cuộc thi này để tự làm điều đó. Nó cũng thú vị hơn theo cách đó. Tất nhiên điều tương tự cũng có thể được nói về BigInt, nhưng sau đó tôi nghi ngờ không ai sẽ thử thách này ...

Chỉnh sửa

  • (630 → 585) Nhận ra Tôi có thể thực hiện hình thức hồi âm trong một vòng thay vì hai. Thêm lời giải thích như ý kiến ​​trong mã.

  • (585 → 583) Chỉ cần phát hiện ra cú pháp gói cho phép tôi sử dụng 'thay vì ::.

  • (583 → 573) Một số microgolfing nữa

  • (573 → 569) Biểu thức chính quy ngắn hơn để phân tích cú pháp đầu vào


Tôi liên tục nhận được lỗi biên dịch: ideone.com/LoB2T
FUZxxl

@FUZxxl: Cảm ơn bạn đã chỉ ra điều đó. Chỉ còn thiếu một khoảng trống. Đã sửa bây giờ.
Timwi

3

TI-Basic (83/84): 109 ký tự

Về mặt kỹ thuật 109 ký tự, TI-Basic đếm mờ (, For (, ->, rref (, [A] và liệt kê là "một ký tự".

Đầu vào được định dạng thành L1 và L2, theo cặp (x, y) [ex L1 = (1,2,3,4), L2 = (2,3,5,7)].

{1,1}->dim([A]
{dim(L1),dim(L2)+1}->dim([A]
For(A,1,dim(L1)
For(B,dim(L1)-1,0,-1
L1(A)^B->[A](A,dim(L1)-B
End
L2(A->[A](A,dim(L1)+1
End
rref([A]->[A]
{0}->L3
For(A,1,dim(L1)
[A](A,dim(L1)+1->L3(A
End
Disp L3

1
Điều này không sử dụng hình thức hợp lý hoặc LaTeX.
lirtosiast

1

Phương pháp Lagrange, Python, 199 byte

Hơi muộn, nhưng ...

def lagrange(dp):
l = lambda i: lambda x: (prod([(x - dp[j][0]) / (dp[i][0] - dp[j][0]) for j in range(len(dp)) if i != j]))
return lambda x: sum([l(i)(x) * dp[i][1] for i in range(len(dp))])

1
Bạn có thể không cần tất cả khoảng trắng xung quanh các toán tử, phải không?

0
l=lambda D,i:lambda x:prod((x-Dj[0])/(D[i][0]-Dj[0])for j,Dj in enumerate(D)if i!=j)
L=lambda D:lambda x:sum(l(D,i)(x)*Di[1]for i,Di in enumerate(D))

Chỉ là một phiên bản rút gọn của mã Fred Freys. Lưu ý rằng người ta có thể bỏ qua việc chuyển D sang l, vì nó chỉ có thể kéo nó từ phạm vi bên ngoài. Như bạn có thể làm điều tương tự với tôi ở đây, chúng tôi thậm chí có thể cạo sạch một lambda. Tôi sẽ kiểm tra nó một ngày nào đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.