ระบุมาตรา Conic


13

รับ 5 คะแนนที่แตกต่างบนระนาบสองมิติ, กำหนดประเภทของส่วนรูปกรวยที่เกิดขึ้นจากคะแนน เอาท์พุทจะเป็นหนึ่งในcircle, hyperbola, หรือellipseparabola

กฎระเบียบ

  • คะแนนจะอยู่ในตำแหน่งเชิงเส้นทั่วไปซึ่งหมายความว่าไม่มีจุดสามจุดเป็นเส้นตรงและทำให้รูปกรวยที่ผ่านจุดเหล่านั้นจะไม่ซ้ำกัน
  • พิกัดของ 5 คะแนนจะเป็นตัวเลขทศนิยมระหว่าง -10 ถึง 10 รวม
  • ความแม่นยำสำหรับค่าทศนิยม / ทศนิยมควรเป็นความแม่นยำของประเภททศนิยม / ทศนิยมของภาษาของคุณ หากภาษา / ชนิดข้อมูลของคุณมีความแม่นยำตามอำเภอใจคุณอาจใช้ตัวเลข 12 หลักหลังจุดทศนิยมเป็นความแม่นยำสูงสุดที่ต้องการโดยปัดเศษเป็นศูนย์ (เช่น1.0000000000005 == 1.000000000000)
  • การใช้ประโยชน์จากตัวพิมพ์ใหญ่ของผลผลิตไม่สำคัญ
  • การส่งออกellipseเมื่อส่วนที่มีรูปกรวยเป็นวงกลมไม่ได้รับอนุญาต แวดวงทั้งหมดเป็นวงรี แต่คุณต้องส่งออกวงกลมที่เฉพาะเจาะจงมากที่สุด

เกี่ยวกับความไม่ถูกต้องของจุดลอยตัวและความแม่นยำ:

ฉันกำลังพยายามทำให้เรื่องนี้ง่ายที่สุดเท่าที่จะทำได้เพื่อให้ปัญหาเกี่ยวกับความไม่ถูกต้องของจุดลอยตัวไม่เข้าทาง เป้าหมายคือถ้าประเภทข้อมูลเป็น "ค่าความแม่นยำไม่มีที่สิ้นสุดวิเศษ" แทนการลอย / สองครั้งทุกอย่างจะทำงานได้อย่างสมบูรณ์แบบ แต่เนื่องจากไม่มี "ค่าความแม่นยำอนันต์มหัศจรรย์" คุณเขียนโค้ดที่ถือว่าค่าของคุณนั้นมีความแม่นยำไม่สิ้นสุดและปัญหาใด ๆ ที่เกิดขึ้นเนื่องจากความไม่ถูกต้องของจุดลอยตัวคือคุณสมบัติไม่ใช่ข้อบกพร่อง

กรณีทดสอบ

(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โฟลตเอาต์พุตดูเหมือนจะต้องมีการตรวจสอบความเท่าเทียมกันแบบลอยเพื่อแยกความแตกต่างจากวงรีที่กลมมาก เราควรคาดเดาสิ่งที่แม่นยำที่นี่
xnor

1
@Mego เหตุใดจึงไม่อนุญาตให้มีปัญหาจำนวนเต็มสำหรับทุกภาษา แต่มีช่วงกว้างกว่าเช่น -10000 ถึง 10,000
orlp

1
คุณแน่ใจหรือว่ากรณีทดสอบสี่ถูกต้อง? desmos: desmos.com/calculator/fmwrjau8fd
Maltysen

2
นอกจากนี้ 3 ดูผิดด้วยเช่นกัน: desmos.com/calculator/tkx1wrkotd
Maltysen

1
ฉันคิดว่าคุณกำลังเข้าใจปัญหาเกี่ยวกับความแม่นยำของ FP และนั่นนำไปสู่คำตอบเช่นcodegolf.stackexchange.com/a/77815/21348
edc65

คำตอบ:


2

Matlab, 154 ไบต์

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

[x1 y1;x2 y2;x3 y3; etc]จะเข้าเป็น สิ่งนี้ใช้เมทริกซ์ Vandermonde และค้นหาพื้นฐานของสเปซว่างซึ่งจะเป็นเวกเตอร์เดียวเสมอ จากนั้นจะคำนวณ discriminant และใช้เพื่อสร้างดัชนีระหว่าง 1 และ 4 ซึ่งใช้ในการรับสตริง

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(...)ส่วนคำนวณจำแนกให้ 1 ถ้ามันบวก (hyperbola) -1 ถ้ามันลบ (วงรี) และ 0 ถ้าเป็น 0 (โค้ง) การmax(...)ลบ 1 ห่างถ้ามันเป็นวงกลม Matlab อาร์เรย์เป็นหนึ่งในดัชนีดังนั้นเพิ่ม 3 เพื่อให้ค่า 1, 2, 3, 4 และใช้เพื่อทำดัชนีอาร์เรย์ของชื่อส่วนรูปกรวย


1
แทนที่จะทำการเปรียบเทียบmax() == 0คุณสามารถลดความซับซ้อนลงได้~max()
Suever

1
นอกจากนี้ones(length(p),1)คุณสามารถทำได้1+p(:,1)*0
Suever

ไชโยmax()สิ่งที่โง่ของฉันฉันมีการเปรียบเทียบก่อนและขี้เกียจชัด! วิธีการได้รับสิ่งonesนั้นก็เป็นสิ่งที่ดีเช่นกัน
เดวิด

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'

ภาษาใดที่เหมาะกับการจัดการเมทริกซ์และดีเทอร์มิแนนต์ควรมีคะแนนที่ดีกว่า (APL, J, CJAM, Jelly)

อ้างอิง: รูปแบบทั่วไปของรูปกรวย , ห้าจุดที่กำหนดรูปกรวย , ระบบสมการเชิงเส้น , ปัจจัย

ในระนาบคาร์ทีเซียนสมการทั่วไปของรูปกรวยคือ

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

มี A หรือ B หรือ C ไม่เท่ากับ 0 (ไม่เช่นนั้นจะเป็นเส้นตรง)

A ... F เป็นสิ่งแปลกปลอมที่พบได้หกแห่ง ด้วยห้าคู่ (x, y) เราสามารถสร้างระบบเชิงเส้นที่มีสมการห้าแบบและปรับขนาดลบหนึ่งมิติ นั่นคือเราสามารถตั้งค่าหนึ่งใน A, B หรือ C เป็น 1 ถ้าไม่ใช่ 0 (และเรารู้ว่าอย่างน้อยหนึ่งไม่ใช่ 0)

ฉันสร้างและลองแก้ปัญหา 3 ระบบก่อนอื่นให้ลอง A = 1 หากไม่สามารถแก้ไขได้แล้ว B = 1 ก็จะเป็น C (อาจเป็นวิธีที่ดีกว่า

มีค่าของ A, B, C เราสามารถจำแนกรูปกรวยที่ดู discriminant d=B*B-4*A*C

  • d == 0 -> พาราโบลา
  • d> 0 -> ไฮเปอร์โบลา
  • d <0 -> วงรีโดยเฉพาะ (A == C และ B == 0) -> วงกลม

น้อย golfed

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

ทดสอบ

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
นี่เป็นสิ่งที่ดีจริงๆ! เยี่ยมมาก!
Alex A.

2

Python - 234 ไบต์

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"

ฉันไม่เคยพิมพ์circleหรือparabolaเพราะtและd[1]ไม่เคยตี0แต่ OP บอกว่าไม่เป็นไร


1

C, 500

คำตอบ JavaScript ของฉันถูกย้ายไปที่ C เพื่อดูว่าสามารถทำได้หรือไม่

การใช้งาน: อ่านค่า 10 ค่าจากอินพุตมาตรฐาน

echo 1 0 0 1 2 1 3 4 4 9 | มีรูปกรวย

เอาท์พุท:

รูปโค้ง

ทดสอบ (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");}

น้อย golfed

// 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 ไบต์

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

ลองออนไลน์

ฟังก์ชั่นนี้จะใช้เวลา iterable ของ(x,y)คู่เป็น input พยายามคำนวณจำแนกของแต่ละระบบเชิงเส้นที่ 3 ที่เป็นไปได้ (คนA=1, B=1และC=1) และผลประเภทของภาคตัดกรวยขึ้นอยู่กับค่านิยมของแนนที่A, และBC

อาจจะมีกอล์ฟให้ทำอีก แต่ตอนนี้ฉันก็เป็นสนิมกับ Sage และง่วงนอนตอนนี้ดังนั้นฉันจะทำงานให้มากขึ้นในตอนเช้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.