Tìm nguồn gốc thực sự của một đa thức


24

Viết một chương trình độc lập mà khi đưa ra một đa thức và một ràng buộc sẽ tìm thấy tất cả các gốc thực sự của đa thức đó với một lỗi tuyệt đối không vượt quá giới hạn.

Những ràng buộc

Tôi biết rằng Mathicala và có lẽ một số ngôn ngữ khác có giải pháp một ký hiệu và điều đó thật nhàm chán, vì vậy bạn nên tuân thủ các thao tác nguyên thủy (cộng, trừ, nhân, chia).

Có sự linh hoạt nhất định trên các định dạng đầu vào và đầu ra. Bạn có thể nhận đầu vào thông qua stdin hoặc đối số dòng lệnh ở bất kỳ định dạng hợp lý nào. Bạn có thể cho phép dấu phẩy động hoặc yêu cầu sử dụng một số biểu diễn số hữu tỷ. Bạn có thể lấy ràng buộc hoặc đối ứng của ràng buộc và nếu bạn đang sử dụng dấu phẩy động, bạn có thể cho rằng giới hạn sẽ không nhỏ hơn 2 ulp. Đa thức nên được biểu thị dưới dạng một danh sách các hệ số đơn thức, nhưng nó có thể là lớn hoặc nhỏ về cuối.

Bạn phải có khả năng biện minh lý do tại sao chương trình của bạn sẽ luôn hoạt động (các vấn đề về số lượng modulo), mặc dù không cần thiết phải cung cấp đầy đủ bằng chứng nội tuyến.

Chương trình phải xử lý đa thức với các gốc lặp đi lặp lại.

Thí dụ

x^2 - 2 = 0 (error bound 0.01)

Đầu vào có thể là ví dụ

-2 0 1 0.01
100 1 0 -2
1/100 ; x^2-2

Đầu ra có thể là ví dụ

-1.41 1.42

nhưng không

-1.40 1.40

vì nó có sai số tuyệt đối khoảng 0,011 ...

Các trường hợp thử nghiệm

Đơn giản:

x^2 - 2 = 0 (error bound 0.01)

x^4 + 0.81 x^2 - 0.47 x + 0.06 (error bound 10^-6)

Nhiều gốc:

x^4 - 8 x^3 + 18 x^2 - 27 (error bound 10^-6)

Đa thức của Wilkinson:

x^20 - 210 x^19 + 20615 x^18 - 1256850 x^17 + 53327946 x^16 -1672280820 x^15 +
    40171771630 x^14 - 756111184500 x^13 + 11310276995381 x^12 - 135585182899530 x^11 +
    1307535010540395 x^10 - 10142299865511450 x^9 + 63030812099294896 x^8 -
    311333643161390640 x^7 + 1206647803780373360 x^6 -3599979517947607200 x^5 +
    8037811822645051776 x^4 - 12870931245150988800 x^3 + 13803759753640704000 x^2 -
    8752948036761600000 x + 2432902008176640000  (error bound 2^-32)

NB Câu hỏi này đã có trong Sandbox trong khoảng 3 tháng. Nếu bạn nghĩ rằng nó cần cải thiện trước khi đăng, hãy truy cập Sandbox và nhận xét về các câu hỏi được đề xuất khác trước khi chúng được đăng trên Main.



@ Belisarius, ??
Peter Taylor

3
được dự định như một trò đùa :(
Tiến sĩ belisarius

Tôi biết đây là một thách thức cũ, vì vậy đừng cảm thấy bắt buộc phải trả lời nếu bạn không muốn mở lại. (a) Chúng ta có thể viết một hàm, hoặc chỉ một chương trình đầy đủ không? (b) Trong trường hợp chúng ta có thể viết một hàm, chúng ta có thể giả sử rằng đầu vào sử dụng một số loại dữ liệu thuận tiện, ví dụ: Python fractions.Fraction(một loại hợp lý) không? (c) Chúng ta có phải xử lý đa thức bậc <1 không? (d) Chúng ta có thể giả sử rằng hệ số dẫn đầu là 1 không?
Ell

(e) Liên quan đến đa thức với các gốc lặp đi lặp lại, đáng để phân biệt giữa các gốc của số lẻ và số chẵn m không chắc chắn mức độ hữu hình của nó để xử lý chính xác các gốc của số nhân chẵn, đặc biệt vì bạn chỉ xác định một lề lỗi cho các giá trị của rễ, không phải cho sự tồn tại của chúng. (...)
Ell

Câu trả lời:


8

Toán học, 223

r[p_,t_]:=Module[{l},l=Exponent[p[x],x];Re@Select[NestWhile[Table[#[[i]]-p[#[[i]]]/Product[If[i!=j,#[[i]]-#[[j]],1],{j,l}],{i,l}]&,Table[(0.9+0.1*I)^i,{i,l}],2*Max[Table[Abs[#1[[i]]-#2[[i]]],{i,l}]]>t&,2],Abs[Im[#]]<t^.5&]]

Giải pháp này thực hiện phương pháp Durandẩu Kerner để giải đa thức. Lưu ý rằng đây không phải là một giải pháp hoàn chỉnh (như sẽ được hiển thị bên dưới) vì tôi chưa thể xử lý Đa thức của Wilkinson với độ chính xác đã chỉ định. Đầu tiên là một lời giải thích về những gì tôi đang làm: mã trong định dạng toán học

#[[i]]-p[#[[i]]]/Product[If[i!=j,#[[i]]-#[[j]],1],{j,l}]&: Do đó, hàm tính toán cho từng chỉ số ixấp xỉ Durand-Kerner tiếp theo. Sau đó, dòng này được gói gọn trong Bảng và được áp dụng bằng NestWhile cho các điểm đầu vào được tạo bởi Table[(0.9+0.1*I)^i,{i,l}]. Điều kiện trên NestWhile là sự thay đổi tối đa (trên tất cả các điều khoản) từ lần lặp này sang lần lặp tiếp theo lớn hơn độ chính xác đã chỉ định. Khi tất cả các điều khoản đã thay đổi ít hơn điều này, NestWhile kết thúc và Re@Selectloại bỏ các số không không thuộc dòng thực.

Ví dụ đầu ra:

> p[x_] := x^2 - 2
> r[p, .01]
{1.41421, -1.41421}

> p[x_] := x^4 - 8 x^3 + 18 x^2 - 27
> r[p, 10^-6]
{2.99999, 3., 3.00001, -1.}

> p[x_] := x^20 - 210 x^19 + ... + 2432902008176640000 (Wilkinson's)
> Sort[r[p, 2^-32]]
{1., 2., 3., 4., 5., 6., 7.00001, 7.99994, 9.00018, 10.0002, 11.0007, \
11.9809, 13.0043, 14.0227, 14.9878, 16.0158, 16.9959, 17.9992, \
19.0001, 20.}

Như bạn có thể thấy, khi mức độ tăng cao hơn, phương pháp này bắt đầu nảy xung quanh các giá trị chính xác, không bao giờ thực sự nở rộ hoàn toàn. Nếu tôi đặt điều kiện dừng của mã của mình là bất cứ điều gì chặt chẽ hơn "từ lần lặp này sang lần đoán tiếp theo thay đổi không quá epsilon" thì thuật toán không bao giờ dừng lại. Tôi đoán tôi chỉ nên sử dụng Durand-Kerner làm đầu vào cho phương pháp của Newton?


Durand-Kerner cũng có vấn đề tiềm ẩn với nhiều gốc. (Phương pháp của Newton cũng không giúp được gì nhiều - đa thức của Wilkinson được chọn đặc biệt là điều hòa).
Peter Taylor

Bạn hoàn toàn chính xác: Tôi đã từ bỏ quá trình hành động đó sau khi phóng to Wilkinson gần x = 17, đó là một mớ hỗn độn tuyệt đối. Tôi lo lắng rằng tôi sẽ phải tìm một giải pháp mang tính biểu tượng với cơ sở Groebner để có được độ chính xác cao hơn nhiều.
Kaya
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.