Konik Bölümü Belirle


13

İki boyutlu bir düzlemde 5 ayrı nokta verildiğinde, noktalardan oluşan konik kesit tipini belirleyin. Çıktı biri olacaktır circle, hyperbola, ellipse, veya parabola.

kurallar

  • Noktalar genel doğrusal pozisyonda olacaktır, yani üç noktanın birbirine yakın olmadığı ve bu nedenle bunlardan geçen konik benzersiz olacaktır.
  • 5 noktanın koordinatları, -10 ile 10 arasındaki ondalık sayılar dahil olacaktır.
  • Ondalık / kayan değerlerin kesinliği, dilinizin yerel kayan / ondalık türünün kesinliği olmalıdır. Diliniz / veri türünüz rasgele kesinlikteyse, ondalık noktadan sonra gereken en yüksek kesinlik olarak 12 basamak kullanabilirsiniz ve sıfıra doğru yuvarlayın (örn. 1.0000000000005 == 1.000000000000).
  • Çıktıdan büyük harf kullanımı önemli değildir.
  • Çıktısı ellipsekonik bölüm aslında bir daire izin verilmez olduğunda. Tüm daireler elips şeklindedir, ancak en belirgin olanı çıkarmanız gerekir.

Kayan nokta yanlışlıklarında ve hassasiyetinde:

Bunu olabildiğince basit hale getirmeye çalışıyorum, böylece kayan nokta yanlışlıkları ile ilgili sorunlar yoluna girmiyor. Amaç, eğer veri türü float / double yerine "sihirli sonsuz kesinlik değeri" olsaydı, o zaman her şey mükemmel çalışırdı. Ancak, "sihirli sonsuz kesinlik değeri" bulunmadığından, değerlerinizin sonsuz kesinlik olduğunu ve kayan nokta yanlışlıkları sonucu ortaya çıkan sorunların hata değil, özellikler olduğunu varsaydığınız bir kod yazarsınız.

Test Durumları

(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
circleŞamandıralar için çıktılar, çok yuvarlak bir elipsten ayırmak için şamandıra eşitliğini kontrol etmeyi gerektirir. Burada ne gibi bir hassasiyet varsaymalıyız?
xnor

1
@Mego Neden tüm diller için sorunun tamsayı sürümüne izin verilmiyor, ancak daha geniş bir aralıkta, örneğin -10000
10000.

1
dördüncü test senaryosunun doğru olduğundan emin misiniz? desmos: desmos.com/calculator/fmwrjau8fd
Maltysen

2
Ayrıca, 3 de yanlış görünüyor: desmos.com/calculator/tkx1wrkotd
Maltysen

1
Bence FP doğruluğu ile ilgili problemleri geçiyorsunuz
77815/

Yanıtlar:


2

Matlab, 154 bayt

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

Suever'in önerileri sayesinde bazı bayt tasarruf etti.

Girişi alır [x1 y1;x2 y2;x3 y3; etc]. Bu bir Vandermonde matrisi kullandı ve her zaman tek bir vektör olacak olan boş uzayının temelini bulur. Daha sonra diskriminant'ı hesaplar ve dizeyi almak için kullanılan 1 ile 4 arasında bir dizin oluşturmak için kullanır.

Ungolfed:

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

sign(...)Bölümü, bu pozitif (hiperbol) ise 1 vererek diskriminant hesaplar, -1 's (elips) negatif ve 0 0 (parabol) ise, eğer. max(...)Toplayıp çıkarmadan 1 uzakta bir daire oluşturuyorsa. Matlab dizileri tek dizinlidir, bu nedenle 1, 2, 3, 4 değerlerini vermek için 3 ekleyin ve bunu konik bölüm adları dizisini dizinlemek için kullanın.


1
Aksine karşılaştırmaktan daha max() == 0Sizin kolaylaştırabilirsiniz~max()
Suever

1
Ayrıca yerine ones(length(p),1)yapabilirsin1+p(:,1)*0
Suever

Şerefe, max()şey benim aptalcaydı, daha önce orada karşılaştırmalar yaptım ve açıkça tembelleştim! Bu şekilde almak da onesçok güzel.
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'

Matris ve determinant kullanımı için daha uygun olan her dil daha iyi puan almalıdır (APL, J, CJAM, Jelly)

Kaynaklar: konik Genel formu , beş noktaları bir konik belirlemek , doğrusal denklem sistemi , Belirleyici

Kartezyen düzlemde, bir koninin genel denklemi

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

A veya B veya C'nin 0'a eşit olmaması (aksi halde düz bir çizgidir)

A ... F bulunacak altı bilinmezdir. Beş çift (x, y) ile beş denklemli doğrusal bir sistem kurabiliriz ve ölçeklendirme bir boyutu kaldırır. Yani, 0 değilse A, B veya C'den birini 1'e ayarlayabiliriz (ve en az birinin 0 olmadığını biliyoruz).

3 sistem kurmaya ve çözmeye çalışıyorum: ilk önce A = 1 deniyor. Çözülemezse B = 1, sonra C (Daha iyi bir yol olabilir, ama o zaman en iyisi)

A, B, C değerlerine sahip olarak, koniği ayrımcıya bakarak sınıflandırabiliriz d=B*B-4*A*C

  • d == 0 -> parabol
  • d> 0 -> hiperbol
  • d <0 -> elips, özellikle (A == C ve B == 0) -> daire

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

Ölçek

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
Bu gerçekten güzel! Harika iş!
Alex

2

Python - 234 bayt

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"

Ben baskı asla circleveya parabolaçünkü tve d[1]tam isabet asla 0ama OP o sorun olmayacağını söyledi.


1

C, 500

JavaScript yanıtım C'ye taşındı. Sadece yapılıp yapılamayacağını görmek için.

Kullanım: standart giriş 10 değerleri okumak

yankı 1 0 0 1 2 1 3 4 4 9 | konik

Çıktı:

Parabol

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

Daha az 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");
}

1

Adaçayı, 247 bayt

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

Çevrimiçi deneyin

Bu fonksiyon, bir iterable alır (x,y)3 olası lineer sistemlerin (her diskriminant işlem dener, girdi olarak çiftler A=1, B=1ve C=1) ve diskriminant, değerlerine göre konik bölümün türü verir A, Bve C.

Muhtemelen daha fazla golf yapılacak, ama şu anda Sage ve uykulu paslıyım, bu yüzden sabah daha fazla çalışacağım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.