Средние углы


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

Как обычно с , представление с наименьшим количеством байтов.

Leaderboard

Вот фрагмент стека, который генерирует как регулярную таблицу лидеров, так и обзор победителей по языкам.

Чтобы убедиться, что ваш ответ обнаружен, начните его с заголовка, используя следующий шаблон уценки:

## 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. Неважно, неправильно прочитал. Может быть? Я не уверен сейчас.
Синий

Хорошо спасибо.
До

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]as 180-(d+180)%360, затем в квадрат. Удобно, когда угол, заданный посредством x/200, уже смещен на 180градусы.


Использование приращений на 1/200самом деле проблематично. Для тестового примера [1, 3, 3]это решение возвращается 2.335и округляется до 2.34правильного ответа 2.33.
Джоэл

@ Джоэл Я не уверен, откуда вы получаете округление, похоже, что десятичные цифры 2.33в этом примере верны . В любом случае, будет изменяя 200к 400или 200072000соответственно) заставить его работать , несмотря на округление? Кроме того, глядя на эту старую проблему еще раз, я думаю, что я мог бы найти лучший путь.
xnor

0,01мзнак равноaрграмммяNИксе(Икс)[s,s+0,01]е(s)<е(s+0,01)|м-s|<|м-s+0,01|роUNd(м)знак равноsее(s)>е(s+0,01)е(s)знак равное(s+0,01)роUNd(м)знак равноs+0,01е

Вот ссылка 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.
Flawr

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 ° , мы можем просто вычислить arccos (cos (πδ ÷ 180 °)) , поскольку cos является как периодическим, так и четным, и arccos всегда дает значение в [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

МАТЛАБ, 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.


Код должен с октавой . Вы можете попробовать это с онлайн переводчиком


1 °, 183 ° должно давать −88 °, а не 92 °.
Андерс Касеорг

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

Нет, неважно. Снова вернемся к чертежной доске ...
Том Карпентер,

1

JavaScript (ES6) 138

Не имея ни малейшего представления об алгоритме, он пробует все возможные значения с точностью до 2 цифр (от -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.