Trung bình của các góc


15

Câu chuyện, hoặc tại sao chúng ta đang làm điều này.

Không ai. Bài tập này hoàn toàn vô nghĩa ... trừ khi bạn là Stephen Hawking .

Các thách thức

Đưa ra một danh sách các góc, tìm trung bình của các góc đó. Ví dụ: trung bình 91 độ và -91 độ là 180 độ. Bạn có thể sử dụng một chương trình hoặc chức năng để làm điều này.

Đầu vào

Một danh sách các giá trị độ đại diện cho các biện pháp góc. Bạn có thể cho rằng chúng sẽ là số nguyên. Chúng có thể được nhập vào trong bất kỳ định dạng thuận tiện hoặc được cung cấp dưới dạng đối số chức năng.

Đầu ra

Trung bình của các giá trị nhập vào. Nếu có nhiều hơn một giá trị được tìm thấy cho mức trung bình, chỉ nên xuất ra một giá trị. Giá trị trung bình được định nghĩa là giá trị

nhập mô tả hình ảnh ở đây

được giảm thiểu. Đầu ra phải nằm trong phạm vi (-180, 180] và chính xác đến ít nhất hai vị trí phía sau dấu thập phân.

Ví dụ:

> 1 3
2
> 90 -90
0 or 180
> 0 -120 120
0 or -120 or 120
> 0 810
45
> 1 3 3
2.33
> 180 60 -60
180 or 60 or -60
> 0 15 45 460
40
> 91 -91
180
> -89 89
0

Như thường lệ với , bài nộp có ít byte nhất sẽ thắng.

Bảng xếp hạng

Dưới đây là Stack Snippet để tạo cả bảng xếp hạng thông thường và tổng quan về người chiến thắng theo ngôn ngữ.

Để đảm bảo rằng câu trả lời của bạn hiển thị, vui lòng bắt đầu câu trả lời của bạn bằng một tiêu đề, sử dụng mẫu Markdown sau:

## Language Name, N bytes

nơi Nlà kích thước của trình của bạn. Nếu bạn cải thiện điểm số của mình, bạn có thể giữ điểm số cũ trong tiêu đề, bằng cách đánh bại chúng thông qua. Ví dụ:

## Ruby, <s>104</s> <s>101</s> 96 bytes

Nếu ở đó bạn muốn bao gồm nhiều số trong tiêu đề của mình (ví dụ: vì điểm của bạn là tổng của hai tệp hoặc bạn muốn liệt kê riêng các hình phạt cờ phiên dịch), hãy đảm bảo rằng điểm thực tế là số cuối cùng trong tiêu đề:

## Perl, 43 + 2 (-p flag) = 45 bytes

Bạn cũng có thể đặt tên ngôn ngữ thành một liên kết mà sau đó sẽ hiển thị trong đoạn trích bảng xếp hạng:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes

Dưới đây là một phòng chat cho bất kỳ câu hỏi nào về vấn đề: http://chat.stackexchange.com/rooms/30175/room-for-aenses-of-angles


Không nên 90, -90 cho 180 nếu 91, -91 cho 180?
Màu xanh

2
Theo trực giác, trung bình của -91 và 91 là 0, không phải 180. Sử dụng định nghĩa của bạn, chúng tôi có: (180-91) ^ 2 + (180- -91) ^ 2 => 81362, trong khi (0-91) ^ 2 + ( 0- -91) ^ 2 => 16562. Vì vậy, 180 chắc chắn không thể là mức trung bình. Tôi đang thiếu gì ở đây?
edc65

91% 360 = 91; -91% 360 = 269; (269 + 91) / 2 = 180. Đừng bận tâm, đọc sai. Có lẽ? Bây giờ tôi không chắc nữa.
Màu xanh

Được rồi cảm ơn. Vẫn không biết làm thế nào để tìm thấy nó
edc65

3
Không có trường hợp thử nghiệm nào của bạn cho đến nay phá vỡ thuật toán không chính xác chỉ đơn giản là lấy tất cả các góc mod 360 °, lấy trung bình của chúng và sau đó trừ 360 ° nếu kết quả lớn hơn 180 °. Bạn nên thêm một trường hợp như [89 °, −89 °], sẽ trả về 0 °.
Anders Kaseorg

Câu trả lời:


7

Python 3, 129 byte

lambda l:min([sum(((b-a)%360)**2for b in l)*len(l)-s*s,180-(180-a-s/len(l))%360]for a in l for s in[sum((b-a)%360for b in l)])[1]

Vấn đề này dường như đã tạo ra khá nhiều nhầm lẫn. Theo trực giác, ý tưởng là cắt vòng tròn các góc tại một số điểm, tháo vòng tròn thành một đường thẳng, tính trung bình số học trên đường thẳng đó, sau đó bọc kết quả trở lại vòng tròn. Nhưng có nhiều điểm khác nhau mà bạn có thể chọn để cắt vòng tròn. Không đủ để chọn một cách tùy tiện, chẳng hạn như 0 ° hoặc 180 °. Bạn cần thử tất cả chúng và xem cái nào dẫn đến tổng khoảng cách bình phương nhỏ nhất. Nếu giải pháp của bạn ít phức tạp hơn đáng kể so với điều này, thì có lẽ sai.


1
@AndreasKaseorg Tôi nghĩ bạn có thể tiết kiệm một byte bằng cách thay đổi s**2thànhs*s
Ioannes

Xem bình luận của tôi về câu hỏi.
msh210

@ msh210 Không chắc tại sao bạn lại gửi bình luận này cho tôi cụ thể. Giải pháp của tôi đã hoạt động theo cách đó.
Anders Kaseorg

Đó là một phần trong câu trả lời cho câu cuối cùng của bài trả lời này.
msh210

4

Python 3, 85 byte

lambda l:180-min(range(72000),key=lambda x:sum((180-(x/200+i)%360)**2for i in l))/200

Tận dụng lợi thế của câu trả lời chỉ cần chính xác đến hai điểm thập phân bằng cách thử tất cả các góc có thể với số gia là 1/200 của một độ. Điều này mất ít hơn một giây trên máy của tôi.

Bởi vì Python không cho phép chúng tôi liệt kê một cách thuận tiện các tiến trình số học của số float, chúng tôi biểu thị các góc có thể là toàn bộ số [0,72000), chuyển đổi thành một góc (-180,180]như x -> 180 - x/200. Chúng tôi tìm thấy một trong số đó cung cấp tổng tối thiểu của các khác biệt góc vuông.

Đối với hai góc có độ dịch chuyển góc d, khoảng cách góc bình phương được tìm thấy bằng cách chuyển đổi thành một góc tương đương (-180,180]theo 180-(d+180)%360, sau đó bình phương. Thuận tiện, góc đưa ra x/200đã được bù bằng 180độ.


Sử dụng gia số 1/200là thực sự có vấn đề. Đối với trường hợp thử nghiệm [1, 3, 3], giải pháp này trả về 2.335và được làm tròn thành 2.34trong khi câu trả lời đúng phải là 2.33.
Joel

@Joel Tôi không chắc bạn đang làm tròn số từ đâu, có vẻ như các chữ số thập phân 2.33ở ngay trong ví dụ đó. Trong mọi trường hợp, việc thay đổi 200thành 400hoặc thành 2000(và 72000tương ứng) sẽ làm cho nó hoạt động mặc dù làm tròn? Ngoài ra, nhìn vào vấn đề cũ này một lần nữa, tôi nghĩ rằng tôi có thể thấy một cách tốt hơn.
xnor

0.01m=argminxf(x)[s,s+0.01]f(s)<f(s+0.01)|ms|<|ms+0.01|round(m)=sff(s)>f(s+0.01)f(s)=f(s+0.01)round(m)=s+0.01f

Đây là một liên kết TIO để bạn kiểm tra.
Joel

Ồ, tôi chỉ nhận ra rằng bạn đúng. Nếu câu trả lời đúng là 2.333...và chương trình của bạn trả về 2.335, nó đúng cho đến hai chữ số thập phân mà không làm tròn số. Xin lỗi vì điều đó.
Joel

3

Octave, 97 95 byte

p=pi;x=p:-1e-5:-p;z=@(L)sum((p-abs(abs(x-mod(L,360)*p/180)-p)).^2);@(L)x(z(L)==min(z(L)))*180/p

Điều này tạo ra một hàm ẩn danh chỉ tìm kiếm mức tối thiểu của hàm đã cho trên một lưới vừa đủ tốt. Khi đầu vào, hàm chấp nhận các vectơ cột, vd [180; 60; -60]. Để kiểm tra bạn cần đặt tên cho hàm. Vì vậy, bạn có thể ví dụ chạy mã ở trên và sau đó sử dụng ans([180, 60; -60]).


Vâng, nó trả về 180.
flawr

2

Javascript ES6, 87 byte

with(Math)f=(...n)=>(t=>180/PI*atan(t(sin)/t(cos)))(f=>n.reduce((p,c)=>p+=f(c*PI/180)))

Ví dụ chạy (Đã kiểm tra trong Firefox):

f(-91,91)     // -0
f(-90,90)     // 0
f(0,-120,120) // 0
f(0,810)      // 44.999999999999936

Công việc đang tiến triển

Phiên bản này có một cách tiếp cận hơi khác so với toán học trung bình-mọi thứ-sau đó-làm-mô-đun. Thay vào đó, các góc được chuyển đổi thành vectơ, vectơ được thêm vào và góc của vectơ kết quả sau đó được tính toán. Thật không may, phiên bản này rất không ổn định với trig và tôi sẽ làm việc trên một phiên bản toán học mô-đun.


1
f(-91,91)sẽ quay lại 180.
TheNumberOne

1
Ngay cả khi nó được thực hiện chính xác, một cách tiếp cận bổ sung vector không thể tính toán kết quả được chỉ định. Ngoài ra vector còn tối đa hóa tổng số cosin của các khác biệt góc, thay vì tối thiểu hóa tổng bình phương của các khác biệt góc.
Anders Kaseorg

2

CJam,  44  40 byte

Ie3_2*,f-:e-2{ea:~f{-P*180/mcmC2#}:+}$0=

Hãy thử trực tuyến trong trình thông dịch CJam .

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

$ for i in 1\ 3 90\ -90 0\ -120\ 120 0\ 810 1\ 3\ 3 180\ 60\ -60 0\ 15\ 45\ 460 91\ -91 -89\ 89
> do cjam <(echo 'Ie3_2*,f-:e-2{ea:~f{-P*180/mcmC2#}:+}$0=') $i
> echo
> done
2.0
180.0
0.0
45.0
2.33
60.0
40.0
180.0
0.0

Ý tưởng

Chúng tôi tính toán độ lệch cho tất cả các trung bình tiềm năng từ -179,99 đến 180,00 với các bước có kích thước 0,01 và chọn một độ lệch có độ lệch thấp nhất.

Với mục đích này, sẽ không có vấn đề gì nếu chúng ta lấy khoảng cách góc độ hoặc radian. Thay vì lập bản đồ khác nhau delta của góc từ đầu vào và trung bình tiềm năng trong [0360 °) và có điều kiện trừ kết quả từ 180 ° , chúng ta có thể chỉ đơn giản là tính toán ArccOS (cos (πδ ÷ 180 °)) , vì cos là cả tuần hoàn và thậm chí, và arccos luôn mang lại một giá trị trong [0, π) .

Ie3        e# Push 18e3 = 18,000.
_2*        e# Copy and multiply by 2. Pushes 36,000.
,          e# Push the range [0 ... 35,999].
f-         e# Subtract each element from 18,000. Pushes [18,000 ... -17,999].
:e-2       e# Divide each element by 100. Pushes [180.00 ... -179.99].
{          e# Sort; for each element A of that array:
  ea:~     e#   Push and evaluate the array of command-line arguments.
  f{       e#   For each input angle, push A and the angle; then:
    -      e#     Subtract the angle from A.
    P*180/ e#     Convert from degrees to radians.
    mcmC   e#     Apply cos, then arccos to the result.
    2#     e#     Square.
  }        e#
  :+       e#   Add the squares. This calculates the deviation.
}$         e# A's with lower deviations come first.
0=         e# Select the first element of the sorted array.

1

MATLAB, 151

p=360;n=mod(input(''),p);a=0:0.01:p;m=[];for b=a e=b-n;f=mod([e;-e],p);c=min(f);d=c.^2;m=[m sum(d)];end;[~,i]=min(m);a=a(i);if a>180 a=a-p;end;disp(a);

Ok, vì vậy cho đến khi tôi thực sự có thể hiểu phương pháp là gì, đây là những gì tôi đã đưa ra. Đó là một chút hack, nhưng như câu hỏi nói rằng câu trả lời phải chính xác đến 2.dp nó sẽ hoạt động.

Về cơ bản, tôi kiểm tra mọi góc giữa 0 và 360 (với số gia 0,01) và sau đó giải công thức trong câu hỏi cho từng góc đó. Sau đó, góc có tổng nhỏ nhất được chọn và chuyển thành phạm vi từ -180 đến 180.


Mã nên với Octave . Bạn có thể thử nó với trình thông dịch trực tuyến


1 °, 183 ° sẽ dẫn đến −88 °, không phải 92 °.
Anders Kaseorg

@AndersKaseorg thử lại ngay bây giờ.
Thợ mộc Tom

Không, đừng bận tâm. Quay lại bảng vẽ một lần nữa ...
Tom Carpenter

1

JavaScript (ES6) 138

Không có ý tưởng mờ nhạt nhất về thuật toán, điều này sẽ thử tất cả các giá trị sở hữu với độ chính xác 2 chữ số (-179,99 đến 180,00). Khá nhanh với các trường hợp thử nghiệm nào.

Kiểm tra chạy đoạn mã dưới đây trong trình duyệt tuân thủ EcmaScript 6 (thực hiện các chức năng mũi tên và tham số mặc định - AFAIK Firefox)

A=l=>(D=(a,b,z=a>b?a-b:b-a)=>z>180?360-z:z,m=>{for(i=-18000;i++<18000;)l.some(v=>(t+=(d=D(v%360,i/100))*d)>m,t=0)||(m=t,r=i)})(1/0)||r/100

// Test
console.log=x=>O.innerHTML+=x+'\n'

;[[1,3],[89,-89],[90,-90],[91,-91],[0,120,-120],[0,810],[1,3,3],[180,60,-60],[0,15,45,460],[1,183]]
.forEach(t=>console.log(t+' -> '+A(t)))

// Less golfed

A=l=>{
  D=(a,b,z=a>b?a-b:b-a) => z>180?360-z:z; // angular distance
  m=1/0;
  for(i=-18000;i++<18000;) // try all from -179.99 to 180
  {
    t = 0;
    if (!l.some(v => (t+=(d=D(v%360,i/100))*d) > m))
    {
      m = t;
      r = i;
    }  
  }  
  return r/100;
}
<pre id=O></pre>

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.