Xác định phần Conic


13

Cho 5 điểm khác biệt trên mặt phẳng hai chiều, xác định loại mặt cắt hình nón được tạo bởi các điểm. Kết quả sẽ là một trong những circle, hyperbola, ellipse, hoặc parabola.

Quy tắc

  • Các điểm sẽ ở vị trí tuyến tính chung, có nghĩa là không có ba điểm nào thẳng hàng, và do đó hình nón đi qua chúng sẽ là duy nhất.
  • Các tọa độ của 5 điểm sẽ là các số thập phân trong khoảng từ -10 đến 10, bao gồm.
  • Độ chính xác cho các giá trị thập phân / float phải là độ chính xác của kiểu float / thập phân gốc của ngôn ngữ của bạn. Nếu loại ngôn ngữ / dữ liệu của bạn là độ chính xác tùy ý, bạn có thể sử dụng 12 chữ số sau dấu thập phân làm độ chính xác yêu cầu tối đa, làm tròn về 0 (ví dụ:1.0000000000005 == 1.000000000000 ).
  • Viết hoa của đầu ra không quan trọng.
  • Xuất ra ellipsekhi phần hình nón thực sự là một vòng tròn không được phép. Tất cả các vòng tròn là hình elip, nhưng bạn phải xuất ra một hình cụ thể nhất.

Về điểm không chính xác và độ chính xác:

Tôi đang cố gắng làm cho điều này trở nên đơn giản nhất có thể, để các vấn đề với sự thiếu chính xác của dấu phẩy động không được giải quyết. Mục tiêu là, nếu kiểu dữ liệu là "giá trị chính xác vô hạn kỳ diệu" thay vì float / double, thì mọi thứ sẽ hoạt động hoàn hảo. Nhưng, vì "giá trị chính xác vô hạn kỳ diệu" không tồn tại, bạn viết mã giả định rằng các giá trị của bạn là độ chính xác vô hạn và bất kỳ vấn đề nào phát sinh do sự thiếu chính xác của dấu phẩy động là các tính năng, không phải lỗi.

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

(0, 0), (1, 5), (2, 3), (4, 8), (9, 2) => hyperbola
(1.2, 5.3), (4.1, 5.6), (9.1, 2.5), (0, 1), (4.2, 0) => ellipse
(5, 0), (4, 3), (3, 4), (0, 5), (0, -5) => circle
(1, 0), (0, 1), (2, 1), (3, 4), (4, 9) => parabola

2
Đối với phao, các đầu ra như circledường như yêu cầu kiểm tra đẳng thức phao để phân biệt với hình elip rất tròn. Độ chính xác nào chúng ta nên giả định ở đây?
xnor

1
@Mego Tại sao không cho phép phiên bản số nguyên của sự cố cho tất cả các ngôn ngữ, nhưng với phạm vi rộng hơn, ví dụ: -10000 đến 10000.
orlp

1
Bạn có chắc chắn trường hợp kiểm tra bốn là chính xác? desmos: desmos.com/calculator/fmwrjau8fd
Maltysen

2
Ngoài ra, 3 cái nhìn cũng sai: desmos.com/calculator/tkx1wrkotd
Maltysen

1
Tôi nghĩ rằng bạn đang đánh giá thấp các vấn đề với độ chính xác của FP và điều đó dẫn đến câu trả lời như codegolf.stackexchange.com/a/77815/21348
edc65

Câu trả lời:


2

Matlab, 154 byte

p=input();c=null([p.^2 prod(p,2) p 1+p(:,1)*0]),s={'circle' 'ellipse' 'parabola' 'hyperbola'};s{3+sign(c(3)^2-4*c(1)*c(2))-~max(abs(c(3)),abs(c(1)-c(2)))}

Đã lưu một số byte nhờ các đề xuất của Suever.

Đưa đầu vào là [x1 y1;x2 y2;x3 y3; etc] . Điều này đã sử dụng ma trận Vandermonde và tìm thấy cơ sở của không gian rỗng, nó sẽ luôn là một vectơ duy nhất. Sau đó, nó tính toán phân biệt đối xử và sử dụng nó để tạo một chỉ mục từ 1 đến 4 được sử dụng để lấy chuỗi.

Ung dung:

p=input();
c=null([p.^2 prod(p')' p ones(length(p),1)]);
s={'circle' 'ellipse' 'parabola' 'hyperbola'};
s{3+sign(c(3)^2-4*c(1)*c(2))-~max(abs(c(3)),abs(c(1)-c(2)))}

Phần sign(...)tính toán phân biệt đối xử, cho 1 nếu nó dương (hyperbola), -1 nếu âm (elip) và 0 nếu 0 (parabola). Các max(...)phép trừ 1 đi nếu nó là một vòng tròn. Mảng Matlab là một chỉ mục, vì vậy hãy thêm 3 để đưa ra các giá trị 1, 2, 3, 4 và sử dụng nó để lập chỉ mục cho mảng tên của phần conic.


1
Thay vì so sánh, max() == 0bạn có thể đơn giản hóa thành~max()
Suever

1
Ngoài ra, thay vì ones(length(p),1)bạn có thể làm1+p(:,1)*0
Suever

Chúc mừng, max()điều đó thật ngớ ngẩn với tôi, tôi đã có sự so sánh ở đó trước đây và rõ ràng là lười biếng! Đó là cách nhận onesđược rất tốt đẹp quá.
David

14

JavaScript (ES6), 316 323 347

p=>[1,2,4].some(x=>(d=D(Q=[[x&1,x&2,x&4,0,0,0],...p.map(([x,y])=>[x*x,x*y,y*y,x,y,1])]))?[a,b,c]=Q.map((v,i)=>D(Q.map((r,j)=>(r=[...r],r[i]=x*!j,r)))/d):0,D=m=>m[1]?m[0].reduce((r,v,i)=>r+(i&1?-v:v)*D(m.slice(1).map(r=>r.filter((a,j)=>j-i))),0):m)&&(d=b*b-4*a*c)?d<0?!b&c==a?'Circle':'Ellipse':'Hyperbola':'Parabola'

Bất kỳ ngôn ngữ nào phù hợp hơn để xử lý ma trận và định thức nên ghi điểm tốt hơn (APL, J, CJAM, Jelly)

Tài liệu tham khảo: Dạng tổng quát của hình nón , Năm điểm xác định hình nón , Hệ phương trình tuyến tính , Định thức

Trong mặt phẳng cartes, phương trình tổng quát của một hình nón là

A*x*x + B*x*y + C*y*y + D*x + E*y + F = 0 

có A hoặc B hoặc C không bằng 0 (nếu không thì đó là một đường thẳng)

A ... F là sáu ẩn số được tìm thấy. Với năm cặp (x, y), chúng ta có thể xây dựng một hệ thống tuyến tính với năm phương trình và chia tỷ lệ loại bỏ một chiều. Nghĩa là, chúng ta có thể đặt một trong A, B hoặc C thành 1 nếu không phải là 0 (và chúng ta biết rằng ít nhất một không phải là 0).

Tôi xây dựng và cố gắng giải quyết 3 hệ thống: đầu tiên thử A = 1. Nếu không thể giải được thì B = 1, sau đó C. (Có thể có cách tốt hơn, nhưng đó là cách tốt nhất của tôi tại thời điểm đó)

Có các giá trị của A, B, C, chúng ta có thể phân loại hình nón nhìn vào phân biệt đối xử d=B*B-4*A*C

  • d == 0 -> parabola
  • d> 0 -> hyperbola
  • d <0 -> hình elip, đặc biệt (A == C và B == 0) -> hình tròn

Ít chơi gôn

F=p=>(
  // Recursive function to find determinant of a square matrix
  D=m=>m[1]
    ?m[0].reduce((r,v,i)=>r+(i&1?-v:v)*D(m.slice(1).map(r=>r.filter((a,j)=>j-i))),0)
    :m,
  // Try 3 linear systems, coefficients in Q
  // Five equation made from the paramaters in p
  // And a first equation with coefficient like k,0,0,0,0,0,1 (example for A)  
  [1,2,4].some(
    x => (
      // matrix to calc the determinant, last coefficient is missing at this stage
      Q = [ 
        [x&1, x&2, x&4, 0,0,0] // first one is different
        // all other equations built from the params 
        ,...p.map( ([x,y]) => [x*x, x*y, y*y, x, y, 1] )
      ],
      d = D(Q), // here d is the determinant
      d && ( // if solvable  then d != 0
        // add missing last coefficient to Q
        // must be != 0 for the first row, must be 0 for the other
        Q.map( r=> (r.push(x), x=0) ),
        // solve the system (Cramer's rule), I get all values for A...F but I just care of a,b,c
        [a,b,c] = Q.map((v,i)=>D(Q.map(r=>(r=[...r],r[i]=r.pop(),r))) / d),
        d = b*b - 4*a*c, // now reuse d for discriminant
        d = d<0 ? !b&c==a ? 'Circle' : 'Ellipse' // now reuse d for end result
        : d ? 'Hyperbola' : 'Parabola'
      ) // exit .some if not 0
    ), d // .some exit with true, the result is in d
  )  
)

Kiểm tra

F=p=>[1,2,4].some(x=>(d=D(Q=[[x&1,x&2,x&4,0,0,0],...p.map(([x,y])=>[x*x,x*y,y*y,x,y,1])]))?[a,b,c]=Q.map((v,i)=>D(Q.map((r,j)=>(r=[...r],r[i]=x*!j,r)))/d):0,D=m=>m[1]?m[0].reduce((r,v,i)=>r+(i&1?-v:v)*D(m.slice(1).map(r=>r.filter((a,j)=>j-i))),0):m)&&(d=b*b-4*a*c)?d<0?!b&c==a?'Circle':'Ellipse':'Hyperbola':'Parabola'

console.log=(...x)=>O.textContent+=x+'\n'

;[
 [[0, 0], [1, 5], [2, 3], [4, 8], [9, 2]]
,[[1.2, 5.3],[4.1, 5.6], [9.1, 2.5], [0, 1], [4.2, 0]]
,[[5, 0], [4, 3], [3, 4], [0, 5], [0, -5]]
,[[1, 0], [0, 1], [2, 1], [3, 4], [4, 9]]
].forEach(t=>console.log(t.join`|`+' => '+F(t)))
<pre id=O></pre>


2
Điều này thực sự tốt đẹp! Làm tốt lắm
Alex A.

2

Python - 234 byte

import numpy as n
x=input()
d=[n.linalg.det(n.delete(n.array([[i*i,i*j,j*j,i,j,1]for i,j in x]),k,1))for k in range(6)]
t=d[1]**2-4*d[0]*d[2]
print"hyperbola"if t>0else"parabola"if t==0else"circle"if d[1]==0and d[0]==d[2]else"ellipse"

Tôi không bao giờ in circlehoặc parabolabởi vì td[1]không bao giờ nhấn chính xác 0, nhưng OP nói rằng điều đó là ổn.


1

C, 500

Câu trả lời JavaScript của tôi được chuyển đến C. Chỉ để xem có thể thực hiện được không.

Cách sử dụng: đọc 10 giá trị từ đầu vào tiêu chuẩn

tiếng vang 1 0 0 1 2 1 3 4 4 9 | hình nón

Đầu ra:

Parabola

Kiểm tra (ideone)

double D(m,k)double*m;{double t=0;for(int s=1,b=1,x=0;x<6;x++,b+=b)k&b||(t+=s*m[x]*(k+b>62?1:D(m+6,k+b)),s=-s);return t;}i,u,h;double m[36],*t=m+6,w[6],s[3],b,d;main(){for(;i++<5;*t++=d*d,*t++=d*b,*t++=b*b,*t++=d,*t++=b,*t++=1)scanf("%lf%lf",&d,&b);for(u=4;u;u/=2)for(m[0]=u&1,m[1]=u&2,m[2]=u&4,d=D(m,0),h=0;d&&h<3;h++){for(i=0;i<6;i++)w[i]=m[i*6+h],m[i*6+h]=i?0:u;s[h]=D(m,0)/d;for(;i--;)m[i*6+h]=w[i];}b=s[1];d=b*b-4*s[0]*s[2];puts(d?d<0?!b&(s[2]==s[0])?"Circle":"Ellipse":"Hyperbola":"Parabola");}

Ít chơi gôn

// Calc determinant of a matrix of side d
// In the golfed code, d is fix to 6
double D(m, d, k)
double*m;
{
    int s = 1, b = 1, x = 0;
    double t = 0;
    for (; x < d; x++, b += b)
        k&b || (
            t += s*m[x] *(k+b+1==1<<d? 1: D(  m + d, d, k + b)), s = -s
        );
    return t;
}

double m[36],d, *t = m + 6, w[6], s[3], a, b, c;
i,u,h;
main()
{
    for (; i++ < 5; )
    {
        scanf("%lf%lf", &a, &b);
        *t++ = a*a, *t++ = a*b, *t++ = b*b, *t++ = a, *t++ = b, *t++ = 1;
    }
    for (u = 4; u; u /= 2)
    {
        m[0] = u & 1, m[1] = u & 2, m[2] = u & 4;
        d = D(m, 6, 0);
        if (d) 
            for (h = 0; h < 3; h++)
            {
                for (i = 0; i < 6; i++)
                    w[i] = m[i * 6 + h],
                    m[i * 6 + h] = i ? 0 : u;
                s[h] = D(m, 6, 0)/d;
                for (; i--; )
                    m[i * 6 + h] = w[i];
            }
    }
    a = s[0], b = s[1], c = s[2];
    d = b*b - 4 * a * c;
    puts(d ? d < 0 ? !b&(c == a) ? "Circle" : "Ellipse" : "Hyperbola" : "Parabola");
}

1

Sage, 247 byte

def f(p):
 for i in[1,2,4]:
  z=[i&1,i&2,i&4,0,0,0]
  M=matrix([z]+[[x*x,x*y,y*y,x,y,1]for x,y in p])
  try:A,B,C=(M\vector(z))[:3]
  except:continue
  d=B*B-4*A*C
  return['parabola','hyperbola','circle','ellipse'][[d==0,d>0,d<0and B==0and A==C,d<0].index(1)]

Dùng thử trực tuyến

Chức năng này có một iterable của (x,y)cặp như đầu vào, cố gắng tính toán biệt thức của mỗi người trong số 3 hệ thống tuyến tính có thể ( A=1, B=1C=1), và kết quả đầu ra các loại đường conic dựa trên các giá trị của biệt thức, A, B, và C.

Có lẽ sẽ có thêm một số hoạt động đánh gôn nữa, nhưng hiện tại tôi rất khó chịu với Sage và buồn ngủ, vì vậy tôi sẽ làm việc với nó nhiều hơn vào buổi sáng.

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.