Rata-rata Sudut

15

Cerita, atau mengapa kita melakukan ini.

Tidak ada Latihan ini sama sekali tidak ada gunanya ... kecuali jika Anda adalah Stephen Hawking .

Tantangan

Diberikan daftar sudut, temukan rata-rata sudut itu. Misalnya rata-rata 91 derajat dan -91 derajat adalah 180 derajat. Anda dapat menggunakan program atau fungsi untuk melakukan ini.

Memasukkan

Daftar nilai derajat yang mewakili ukuran sudut. Anda dapat mengasumsikan bahwa mereka akan menjadi bilangan bulat. Mereka dapat dimasukkan dalam format yang mudah digunakan atau disediakan sebagai argumen fungsi.

Keluaran

Rata-rata dari nilai yang dimasukkan. Jika ada lebih dari satu nilai yang ditemukan untuk rata-rata, hanya satu yang harus dikeluarkan. Rata-rata didefinisikan sebagai nilai

masukkan deskripsi gambar di sini

diminimalkan. Output harus berada dalam kisaran (-180, 180] dan akurat untuk setidaknya dua tempat di belakang titik desimal.

Contoh:

> 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

Seperti biasa dengan , pengiriman dengan byte paling sedikit menang.

Papan peringkat

Berikut ini adalah Stack Snippet untuk menghasilkan leaderboard biasa dan gambaran umum pemenang berdasarkan bahasa.

Untuk memastikan bahwa jawaban Anda muncul, silakan mulai jawaban Anda dengan tajuk utama, menggunakan templat Penurunan harga berikut:

## Language Name, N bytes

di mana Nukuran kiriman Anda. Jika Anda meningkatkan skor Anda, Anda dapat menyimpan skor lama di headline, dengan mencoretnya. Contohnya:

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

Jika ada yang ingin Anda sertakan beberapa nomor di header (misalnya karena skor Anda adalah jumlah dari dua file atau Anda ingin daftar juru hukuman bendera secara terpisah), memastikan bahwa skor aktual adalah terakhir nomor dalam header:

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

Anda juga dapat membuat tautan nama bahasa yang kemudian akan muncul di cuplikan papan peringkat:

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

Berikut adalah ruang obrolan untuk pertanyaan apa pun tentang masalah ini: http://chat.stackexchange.com/rooms/30175/room-for-average-of-angles

TheNumberOne
sumber
Bukankah seharusnya 90, -90 memberi 180 jika 91, -91 memberi 180?
Biru
2
Secara intuitif rata-rata -91 dan 91 adalah 0, bukan 180. Menggunakan definisi Anda, kami memiliki: (180-91) ^ 2 + (180- -91) ^ 2 => 81362, sementara (0-91) ^ 2 + ( 0- -91) ^ 2 => 16562. Jadi 180 pasti tidak bisa menjadi rata-rata. Apa yang kulewatkan di sini?
edc65
91% 360 = 91; -91% 360 = 269; (269 + 91) / 2 = 180. Sudahlah, salah baca. Mungkin? Saya tidak yakin sekarang.
Biru
Ok terima kasih. Masih tidak tahu bagaimana menemukannya
edc65
3
Sejauh ini tidak ada kasus uji yang memecahkan algoritma yang salah dengan hanya mengambil semua sudut mod 360 °, mengambil rata-rata, dan kemudian mengurangi 360 ° jika hasilnya lebih besar dari 180 °. Anda harus menambahkan case seperti [89 °, −89 °], yang seharusnya mengembalikan 0 °.
Anders Kaseorg

Jawaban:

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]

Masalah ini sepertinya telah menimbulkan banyak kebingungan. Secara intuitif, idenya adalah untuk memotong lingkaran sudut di beberapa titik, membuka lingkaran ke garis, menghitung rata-rata aritmatika pada garis itu, dan kemudian membungkus hasilnya kembali ke lingkaran. Tetapi ada banyak titik berbeda di mana Anda dapat memilih untuk memotong lingkaran. Tidak cukup dengan hanya memilih satu, seperti 0 ° atau 180 °. Anda harus mencoba semuanya dan melihat mana yang menghasilkan jumlah terkecil dari jarak kuadrat. Jika solusi Anda jauh lebih mudah daripada ini, itu mungkin salah.

Anders Kaseorg
sumber
1
@AndreasKaseorg Saya pikir Anda dapat menyimpan satu byte dengan mengubah s**2kes*s
Ioannes
Lihat komentar saya pada pertanyaan.
msh210
@ msh210 Tidak yakin mengapa Anda mengarahkan komentar ini kepada saya secara khusus. Solusi saya sudah bekerja seperti itu.
Anders Kaseorg
Itu sebagian sebagai balasan dari kalimat terakhir dari posting jawaban ini.
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

Mengambil keuntungan dari jawaban hanya perlu akurat ke dua titik desimal dengan mencoba semua sudut yang mungkin dengan kenaikan 1/200derajat. Ini membutuhkan waktu kurang dari satu detik di mesin saya.

Karena Python tidak membiarkan kita dengan mudah mendaftar progres aritmatika dari floats, kami mewakili sudut yang mungkin sebagai bilangan bulat [0,72000), yang dikonversi menjadi sudut sama (-180,180]dengan x -> 180 - x/200. Kami menemukan salah satu dari ini yang memberikan jumlah minimum dari perbedaan sudut kuadrat.

Untuk dua sudut dengan perpindahan sudut dari d, jarak sudut kuadrat ditemukan dengan mengubah ke sudut setara dalam (-180,180]sebagai 180-(d+180)%360, kemudian mengkuadratkan. Dengan mudah, sudut yang diberikan x/200sudah diimbangi dengan 180derajat.

Tidak
sumber
Menggunakan peningkatan 1/200sebenarnya bermasalah. Untuk kasus uji [1, 3, 3], solusi ini kembali 2.335dan dibulatkan ke 2.34saat jawaban yang benar seharusnya 2.33.
Joel
@ Joel Saya tidak yakin dari mana Anda mendapatkan pembulatan, sepertinya angka desimal 2.33tepat dalam contoh itu. Dalam kasus apa pun, akankah mengubah 200to 400atau ke 2000(dan juga 72000) membuatnya berfungsi meskipun pembulatan? Juga, melihat masalah lama ini lagi, saya pikir saya mungkin melihat cara yang lebih baik.
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
Berikut ini adalah tautan TIO untuk Anda uji.
Joel
Oh, aku baru sadar kalau kamu benar. Jika jawaban yang benar adalah 2.333...dan program Anda kembali 2.335, itu benar sampai dua tempat desimal tanpa pembulatan. Maaf untuk itu.
Joel
3

Oktaf, 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

Ini menghasilkan fungsi anonim yang hanya mencari minimum dari fungsi yang diberikan pada kotak yang cukup baik. Sebagai input fungsi menerima vektor kolom, mis [180; 60; -60]. Untuk pengujian Anda perlu memberi nama fungsi. Jadi Anda bisa mis. Jalankan kode di atas dan kemudian gunakan ans([180, 60; -60]).

cacat
sumber
Ya, ia mengembalikan 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)))

Contoh berjalan (Diuji di Firefox):

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

Bekerja dalam proses

Versi ini mengambil pendekatan yang sedikit berbeda dari rata-rata-semuanya-kemudian-lakukan-modular-matematika. Alih-alih, sudut dikonversi menjadi vektor, vektor ditambahkan dan sudut vektor yang dihasilkan kemudian dihitung. Sayangnya, versi ini sangat tidak stabil dengan trigonometri dan saya akan mengerjakan versi modular-matematika.

Dendrobium
sumber
1
f(-91,91)harus mengembalikan 180.
TheNumberOne
1
Bahkan jika itu diterapkan dengan benar, pendekatan penambahan vektor tidak dapat menghitung hasil yang ditentukan. Penambahan vektor memaksimalkan jumlah cosinus dari perbedaan sudut, daripada meminimalkan jumlah kuadrat dari perbedaan sudut.
Anders Kaseorg
2

CJam,  44  40 byte

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

Cobalah online di penerjemah CJam .

Uji kasus

$ 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

Ide

Kami menghitung deviasi untuk semua rata-rata potensial dari -179,99 hingga 180,00 dengan langkah-langkah ukuran 0,01 , dan pilih satu dengan deviasi terendah.

Untuk tujuan ini, tidak masalah jika kita mengambil derajat sudut radian atau radian. Daripada memetakan perbedaan δ sudut dari input dan potensial rata-rata di [0,360 °) dan dengan mengurangkan hasil dari 180 ° secara kondisional , kita bisa menghitung arccos (cos (πδ ÷ 180 °)) , karena cos bersifat periodik dan genap, dan arccos selalu menghasilkan nilai dalam [0, π) .

Kode

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.
Dennis
sumber
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, jadi sampai saya benar-benar bisa mengerti apa metodologinya, inilah yang saya buat. Ini sedikit meretas, tetapi karena pertanyaannya menyatakan bahwa jawabannya harus benar untuk 2.dp itu harus bekerja.

Saya pada dasarnya memeriksa setiap sudut antara 0 dan 360 (dalam penambahan 0,01) dan kemudian menyelesaikan rumus dalam pertanyaan untuk masing-masing sudut tersebut. Kemudian sudut dengan jumlah terkecil diambil dan dikonversi menjadi -180 hingga 180 range.


Kode harus dengan Oktaf . Anda dapat mencobanya dengan juru bahasa online

Tom Carpenter
sumber
1 °, 183 ° harus menghasilkan −88 °, bukan 92 °.
Anders Kaseorg
@AndersKaseorg coba lagi sekarang.
Tom Carpenter
Tidak, sudahlah. Kembali ke papan gambar lagi ...
Tom Carpenter
1

JavaScript (ES6) 138

Tidak memiliki gagasan samar tentang suatu algoritma, ini mencoba semua nilai kemungkinan dengan presisi 2 digit (-179,99 hingga 180,00). Cukup cepat dengan test case-nya.

Tes menjalankan cuplikan di bawah ini di peramban yang mendukung EcmaScript 6 (menerapkan fungsi panah dan parameter default - 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>

edc65
sumber