Identifikasi Bagian Kerucut

13

Diberikan 5 titik berbeda pada bidang dua dimensi, tentukan jenis penampang kerucut yang dibentuk oleh titik tersebut. Output akan menjadi satu dari circle, hyperbola, ellipse, atau parabola.

Aturan

  • Titik-titik akan berada pada posisi linear umum, yang berarti bahwa tidak ada tiga titik yang collinear, dan dengan demikian kerucut yang melewatinya akan menjadi unik.
  • Koordinat dari 5 poin akan berupa angka desimal antara -10 dan 10, inklusif.
  • Ketepatan untuk nilai desimal / float haruslah ketepatan jenis float / desimal asli bahasa Anda. Jika bahasa / tipe data Anda memiliki ketelitian yang arbitrer, Anda dapat menggunakan 12 digit setelah titik desimal sebagai ketelitian maksimum yang diperlukan, membulatkan ke nol (misalnya 1.0000000000005 == 1.000000000000).
  • Kapitalisasi output tidak menjadi masalah.
  • Mengeluarkan ellipseketika bagian kerucut sebenarnya lingkaran tidak diizinkan. Semua lingkaran adalah elips, tetapi Anda harus menampilkan yang paling spesifik.

Pada ketidakakuratan dan presisi floating point:

Saya mencoba membuat ini sesederhana mungkin, sehingga masalah dengan ketidakakuratan floating point tidak menghalangi. Tujuannya adalah, jika tipe data adalah "nilai presisi magis tak terbatas" alih-alih float / double, maka semuanya akan bekerja dengan sempurna. Tetapi, karena "nilai ketelitian tak terbatas magis" tidak ada, Anda menulis kode yang mengasumsikan bahwa nilai Anda adalah ketepatan tak terbatas, dan setiap masalah yang muncul sebagai akibat ketidakakuratan titik mengambang adalah fitur, bukan bug.

Uji Kasus

(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
Mego
sumber
2
Untuk pelampung, keluaran seperti circletampaknya membutuhkan pemeriksaan kesetaraan pelampung untuk membedakan dari elips yang sangat bulat. Apa presisi yang harus kita asumsikan di sini?
xnor
1
@Mego Mengapa tidak mengizinkan versi integer masalah untuk semua bahasa, tetapi dengan rentang yang lebih luas, misalnya -10000 hingga 10000.
orlp
1
Anda yakin test case empat benar? desmos: desmos.com/calculator/fmwrjau8fd
Maltysen
2
Juga, 3 terlihat salah juga: desmos.com/calculator/tkx1wrkotd
Maltysen
1
Saya pikir Anda meremehkan masalah dengan akurasi FP, dan itu mengarah ke jawaban seperti codegolf ini.stackexchange.com/a/77815/21348
edc65

Jawaban:

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

Menyimpan beberapa byte berkat saran Suever.

Mengambil input sebagai [x1 y1;x2 y2;x3 y3; etc]. Ini menggunakan matriks Vandermonde, dan menemukan dasar ruang nolnya, yang akan selalu menjadi vektor tunggal. Kemudian menghitung diskriminan dan menggunakannya untuk membuat indeks antara 1 dan 4 yang digunakan untuk mendapatkan string.

Tidak Disatukan:

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

Bagian sign(...)menghitung diskriminan, memberi 1 jika itu positif (hiperbola), -1 jika itu negatif (elips), dan 0 jika itu 0 (parabola). The max(...)mengurangi 1 pergi jika itu adalah lingkaran. Array Matlab adalah satu-diindeks, jadi tambahkan 3 untuk memberikan nilai 1, 2, 3, 4, dan gunakan itu untuk mengindeks array nama bagian kerucut.

David
sumber
1
Daripada membandingkan, max() == 0Anda dapat menyederhanakannya~max()
Suever
1
Selain itu, ones(length(p),1)Anda tidak dapat melakukannya1+p(:,1)*0
Suever
Sorak-sorai, max()hal itu konyol bagi saya, saya memang punya perbandingan di sana sebelumnya dan jelas malas! Cara mendapatkan itu onesjuga sangat bagus.
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'

Bahasa apa pun yang lebih cocok untuk menangani matriks dan penentu harus mendapat skor yang lebih baik (APL, J, CJAM, Jelly)

Referensi: Bentuk umum kerucut , Lima poin menentukan kerucut , Sistem persamaan linear , Penentu

Dalam bidang kartesius, persamaan umum dari sebuah kerucut adalah

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

memiliki A atau B atau C tidak sama dengan 0 (kalau tidak itu adalah garis lurus)

A ... F adalah enam yang tidak diketahui yang dapat ditemukan. Dengan lima pasang (x, y) kita dapat membangun sistem linier dengan lima persamaan, dan penskalaan menghapus satu dimensi. Yaitu, kita dapat mengatur satu dari A, B atau C ke 1 jika bukan 0 (dan kita tahu bahwa setidaknya satu bukan 0).

Saya membangun dan mencoba menyelesaikan 3 sistem: pertama mencoba A = 1. Jika tidak dapat dipecahkan maka B = 1, maka C. (Mungkin ada cara yang lebih baik, tapi itu yang terbaik saat itu)

Memiliki nilai-nilai A, B, C kita dapat mengklasifikasikan kerucut melihat diskriminan d=B*B-4*A*C

  • d == 0 -> parabola
  • d> 0 -> hiperbola
  • d <0 -> ellipse, khususnya (A == C dan B == 0) -> lingkaran

Kurang golf

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

Uji

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>

edc65
sumber
2
Ini sangat bagus! Kerja bagus!
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"

Saya tidak pernah mencetak circleatau parabolakarena tdan d[1]tidak pernah menekan persis 0, tetapi OP mengatakan itu baik-baik saja.

Maltysen
sumber
1

C, 500

Jawaban JavaScript saya porting ke C. Hanya untuk melihat apakah itu bisa dilakukan.

Penggunaan: membaca 10 nilai dari input standar

echo 1 0 0 1 2 1 3 4 4 9 | berbentuk kerucut

Keluaran:

Parabola

Tes (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");}

Kurang golf

// 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");
}
edc65
sumber
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)]

Cobalah online

Fungsi ini mengambil iterable dari (x,y)pasangan sebagai masukan, mencoba menghitung diskriminan dari masing-masing 3 kemungkinan sistem linear ( A=1, B=1, dan C=1), dan output jenis irisan kerucut berdasarkan nilai-nilai diskriminan, A, B, dan C.

Mungkin ada beberapa golf yang harus dilakukan, tapi aku berkarat dengan Sage dan mengantuk sekarang, jadi aku akan mengerjakannya lebih banyak di pagi hari.

Mego
sumber