Середні значення кутів


15

Історія, або чому ми це робимо.

Жоден. Ця вправа абсолютно безглузда ... якщо ви не Стівен Хокінг .

Змагання

Давши список кутів, знайдіть середнє значення цих кутів. Наприклад, в середньому 91 градус і -91 градус - 180 градусів. Ви можете використовувати програму або функцію для цього.

Вхідні дані

Перелік значень ступеня, що представляють міри кута. Ви можете припустити, що вони будуть цілими числами. Вони можуть бути введені в будь-якому зручному форматі або подані як аргументи функції.

Вихідні дані

Середнє значення введених значень. Якщо в середньому знайдено більше одного значення, слід вивести лише одне. Середнє значення визначається як значення, для якого

введіть тут опис зображення

зводиться до мінімуму. Вихід повинен бути в межах (-180, 180] і бути точним як мінімум на два місця за десятковою точкою.

Приклади:

> 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

Як зазвичай це , подання з найменшими байтами.

Таблиця лідерів

Ось фрагмент стека для створення як звичайного табло, так і огляду переможців за мовою.

Щоб переконатися, що ваша відповідь відображається, будь ласка, почніть свою відповідь із заголовка, використовуючи наступний шаблон Markdown:

## Language Name, N bytes

де Nрозмір вашого подання. Якщо ви покращите свій рахунок, ви можете зберегти старі бали у заголовку, прокресливши їх. Наприклад:

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

Якщо ви хочете включити у свій заголовок декілька чисел (наприклад, тому що ваш рахунок становить суму двох файлів або ви хочете окремо перерахувати штрафні санкції для перекладача), переконайтесь, що фактичний бал є останнім номером у заголовку:

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

Ви також можете зробити ім'я мови посиланням, яке потім з’явиться у фрагменті таблиць лідерів:

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

Ось чат для будь-яких питань щодо проблеми: http://chat.stackexchange.com/rooms/30175/room-for-average-of-angles


Чи не слід 90, -90 давати 180, якщо 91, -91 дає 180?
Блакитний

2
Інтуїтивно середнє значення -91 та 91 дорівнює 0, а не 180. Використовуючи ваше визначення, ми маємо: (180-91) ^ 2 + (180- -91) ^ 2 => 81362, тоді як (0-91) ^ 2 + ( 0- -91) ^ 2 => 16562. Тож 180 точно не може бути середнім. Що я тут пропускаю?
edc65

91% 360 = 91; -91% 360 = 269; (269 + 91) / 2 = 180. Неважливо, непрочитано. Можливо? Я зараз не впевнений.
Блакитний

Добре, дякую. Досі не маю уявлення про те, як його знайти
edc65

3
Жоден з ваших тестових випадків досі не порушує неправильний алгоритм просто взяти всі кути мод 360 °, взявши їх середнє значення, а потім відняти 360 °, якщо результат перевищує 180 °. Ви повинні додати випадок на зразок [89 °, −89 °], який повинен повернути 0 °.
Андерс Касеорг

Відповіді:


7

Python 3, 129 байт

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]

Ця проблема, здається, породила досить багато плутанини. Інтуїтивно зрозуміло, що в якийсь момент вирізати коло кутів, розкрутити коло до лінії, обчислити середнє арифметичне на цій прямій, а потім повернути результат назад до кола. Але є багато різних точок, де можна було вирішити вирізати коло. Довільно вибрати один, наприклад 0 ° або 180 °, недостатньо. Вам потрібно спробувати їх усіх і побачити, який з них приводить до найменшої суми відстаней у квадраті. Якщо ваше рішення значно менш складне, ніж це, можливо, це неправильно.


1
@AndreasKaseorg Я думаю, що ви можете зберегти один байт, змінивши s**2наs*s
Іоанн

Дивіться мій коментар до питання.
msh210

@ msh210 Не впевнений, чому саме ти скеровуєш цей коментар саме до мене. Моє рішення вже працює таким чином.
Андерс Касеорг

Частково це було відповіді на останнє речення цього відповіді.
msh210

4

Python 3, 85 байт

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

Користується відповіддю лише необхідною точністю до двох знаків після коми, спробувавши всі можливі кути з кроком 1/200на градус. На моїй машині це займає менше секунди.

Оскільки Python не дозволяє нам зручно перераховувати арифметичні прогресії плавців, ми представляємо можливі кути як ціле число [0,72000), яке перетворюється на кут (-180,180]як x -> 180 - x/200. Ми знаходимо одну з них, яка дає мінімальну суму різниць кутових різниць.

Для двох кутів з кутовим зміщенням dкутове відстань у квадраті знаходять шляхом перетворення на еквівалентний кут у (-180,180]як 180-(d+180)%360, а потім квадратування. Зручно, що кут, заданий, x/200вже зміщений на 180градуси.


Використання приростів 1/200фактично проблематично. Для тестового випадку [1, 3, 3]це рішення повертається 2.335і округлюється до того часу, 2.34поки має бути правильна відповідь 2.33.
Джоель

@Joel Я не впевнений, звідки ви отримуєте округлення, схоже, десяткові цифри 2.33є правильними в цьому прикладі. У будь-якому випадку, буде змінюючи 200до 400або 200072000відповідно) змусити його працювати , незважаючи на округлення? Також, переглядаючи цю стару проблему ще раз, я думаю, що я можу побачити кращий спосіб.
xnor

0,01м=аrгмiнхf(х)[с,с+0,01]f(с)<f(с+0,01)|м-с|<|м-с+0,01|rоунг(м)=сff(с)>f(с+0,01)f(с)=f(с+0,01)round(m)=s+0.01f

Ось посилання TIO, яке ви можете протестувати.
Джоель

О, я щойно зрозумів, що ти маєш рацію. Якщо правильна відповідь є 2.333...і ваша програма повернеться 2.335, вона буде правильною до двох десяткових знаків без округлення. Вибачте за це.
Джоель

3

Октава, 97 95 байт

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

Це створює анонімну функцію, яка просто шукає мінімум заданої функції в сітці, що достатньо добре. В якості введення функція приймає вектори стовпців, наприклад [180; 60; -60]. Для тестування потрібно вказати ім'я функції. Таким чином, ви можете, наприклад, запустити код вище, а потім використовувати ans([180, 60; -60]).


Так, повертається 180.
Недолік

2

Javascript ES6, 87 байт

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

Приклад запуску (випробуваний у Firefox):

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

Робота в процесі

Ця версія має дещо інший підхід, ніж середня математика "все, що робити, то робити". Швидше за все, кути перетворюються на вектори, додаються вектори і потім обчислюється кут отриманого вектора. На жаль, ця версія дуже нестабільна з тригером, і я працюю над модульно-математичною версією.


1
f(-91,91)має повернутись 180.
TheNumberOne

1
Навіть якщо він був реалізований правильно, підхід додавання вектора не може обчислити заданий результат. Векторне додавання максимізує суму косинусів кутових різниць, а не мінімізує суму квадратів кутових різниць.
Андерс Касеорг

2

CJam,  44  40 байт

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

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Тестові справи

$ 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

Ідея

Ми обчислюємо відхилення для всіх потенційних середніх значень від -179,99 до 180,00 з кроком розміром 0,01 і вибираємо одне з найменшим відхиленням.

Для цього не має значення, чи будемо ми брати градусні або кутові відстані. Замість того, щоб відобразити різниці δ кутів від вхідних та потенційних середніх значень [0,360 °) та умовно відняти результат від 180 ° , ми можемо просто обчислити дуги (cos (πδ ÷ 180 °)) , оскільки cos є періодичним і рівним, і дуги завжди дають значення в [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);

Добре, так що поки я не можу зрозуміти, що таке методологія, це те, що я придумав. Це трохи хак, але оскільки запитання вказує, що відповідь повинна бути правильною для 2.dp, вона повинна спрацювати.

Я в основному перевіряю кожен кут між 0 і 360 (з кроком 0,01), а потім вирішую формулу у питанні для кожного з цих кутів. Потім вибирається кут з найменшою сумою і перетворюється в діапазон від -180 до 180.


Код повинен бути з Octave . Ви можете спробувати з онлайн-перекладачем


1 °, 183 ° має призвести до –88 °, а не 92 °.
Anders Kaseorg

@AndersKaseorg спробуйте ще раз.
Том Карпентер

Ні, неважливо. Знову повертаємось до дошки для малювання ...
Том Карпентер

1

JavaScript (ES6) 138

Не маючи найменшого уявлення про алгоритм, він намагається виконати всі можливі значення з двозначною точністю (від -179,99 до 180,00). Досить швидко з тестовими справами все одно.

Випробуйте запуск фрагмента нижче у веб-переглядачі, сумісному з EcmaScript 6 (реалізуючи функції стрілок та параметри за замовчуванням - 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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.