Введение
При создании проекта электроники схема может потребовать резистор необычного значения (скажем, 510 Ом). Вы проверяете свою корзину для запчастей и обнаруживаете, что у вас нет резисторов на 510 Ом. Но у вас есть много общих значений выше и ниже этого значения. Комбинируя резисторы параллельно и последовательно, вы должны быть в состоянии достаточно хорошо аппроксимировать резистор 510 Ом.
задача
Вы должны написать функцию или программу, которая принимает список значений резисторов (резисторы, которые вы используете) и целевое значение (которое вы стремитесь приблизить). Программа должна учитывать:
- Индивидуальные резисторы
- Два резистора в серии
- Два резистора параллельно
Программа должна вычислить все возможные комбинации 1 и 2 резисторов из списка запасов (включая две копии одного и того же значения резистора), вычислить их серии и параллельное сопротивление, а затем отсортировать конфигурации в соответствии с тем, насколько они приближаются к целевому значению.
Выходным форматом должна быть одна конфигурация на строку с +
обозначением серии и |
параллелью, а также некоторого пробела или знака = перед чистым сопротивлением.
Формулы
- Сопротивление одного резистора
R1
- Сопротивление двух последовательных резисторов равно
R1 + R2
- Чистое сопротивление двух резисторов параллельно
1 / (1/R1 + 1/R2)
- Расстояние между аппроксимированным значением сопротивления и целевым значением может быть вычислено как псевдо-логарифмическим расстояние, а не линейным расстояния:
dist = abs(Rapprox / Rtarget - 1)
. Например, 200 ближе к 350, чем к 100. - Лучшим показателем расстояния является истинное логарифмическое расстояние
dist = abs(log(Rapprox/Rtarget))
, но, поскольку оно не было указано в исходном вопросе, вы можете использовать любое измерение.
счет
Оценка измеряется в символах кода, согласно обычным правилам игры в гольф. Самый низкий балл побеждает.
пример
У нас есть следующие резисторы на складе, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700]
и мы хотим нацелиться на 510
ом. Программа должна вывести 143 конфигурации, примерно так, как показано (вы можете изменить формат, но убедитесь, что значение легко определить):
680 | 2200 519.444
1000 | 1000 500.
150 + 330 480.
220 + 330 550.
470 470
680 | 1500 467.89
680 | 3300 563.819
100 + 470 570.
220 + 220 440.
100 + 330 430.
470 | 4700 427.273
680 | 4700 594.052
1000 | 1500 600.
470 | 3300 411.406
680 | 1000 404.762
150 + 470 620.
...
many more rows
...
2200 + 4700 6900.
3300 + 4700 8000.
4700 + 4700 9400.
В этом примере наилучшее приближение в 510 Ом дается параллельными резисторами 680 и 2200 Ом.
Лучшее на каждом языке (1 июня 2014 г.):
- J - 70 символов
- APL - 102 символа
- Mathematica - 122 символа
- Рубин - 154 символа
- Javascript - 156 символов
- Юлия - 163 символа
- Perl - 185 символов
- Python - 270 знаков
Ответы:
J -
867170 символовЯ не собираюсь объяснять каждую мелочь, потому что большая часть кода тратится на синхронизацию результатов различных функций, но вот суть игры в гольф:
;@((<@,.{:)\)
создает все возможные пары резисторов, которые должны быть подключены параллельно или последовательно.[:,/(<,.+`|,.+/;+&.%/)"1@
затем соединяет их параллельно и последовательно, составляя большой список возможных соединений.(;a:,<)"0,
добавляет возможность использования только одного резистора в качестве приблизительного.(]/:[|@<:@%~2{::"1])
сортирует список комбинаций резисторов по псевдологическому расстоянию (|@<:@%
) между целью и результирующим сопротивлением от каждой комбинации.И вот как это использовать:
Вам не нужно просматривать только первые 10, как я делал выше, но это функция, и J REPL усекает очень большие возвращаемые значения, а полный вывод для этого примера имеет 287 строк. Вы можете заставить все это перейти в STDOUT с помощью чего-то похожего
tmoutput toCRLF , LF ,.~ ": blah rouv blah
на Windows - сброситьtoCRLF
на Linux - ноrouv
это функция, и внутри все строки существуют.Заметка:
Вопрос, похоже, был изменен прямо у нас под носом, и теперь логарифмическое расстояние определяется как
abs(log(Rapprox/Rtarget))
вместоabs(Rapprox/Rtarget-1)
. Чтобы исправить это в моем гольфе, мы можем изменить|@<:@%
к|@^.@%
:<:
это Decrement в то время как^.
это логарифм.источник
Mathematica,
151122 символовОжидается сохранение целевого сопротивления
r
и список доступных резисторовl
.Меньше гольфа:
Выходной формат отличается от предложенного, но конфигурации легко определить. Вывод представляет собой список конфигураций. Каждая конфигурация имеет одну из следующих форм:
Итак, первые три элемента вывода читаются
Если у вас все в порядке с рациональными числами, я мог бы уберечь два символа от пропуска
N@
. То есть первый элемент (например) будет возвращен как4675/9
вместо519.444
.источник
APL (102)
Это принимает целевое сопротивление в качестве левого аргумента и список доступных резисторов в качестве правого аргумента.
Объяснение:
V←{
...}
:V
это функция, которая:Z/⍨≤/¨Z←,∘.,⍨⍵
: находит каждую уникальную комбинацию двух значений в⍵
,Z←,∘.,⍨⍵
: объединить каждое значение⍵
с каждым значением в⍵
, сохранить вZ
,Z/⍨≤/¨Z
: выберите изZ
тех комбинаций, где первое значение меньше или равно второму значению⍺{
...}⍺⍺/¨
: и затем применяет следующую функцию, связанную с левой функцией (⍺⍺
) справа и левым аргументом (⍺
) слева, к каждой паре:⍺,⍺⍺,⍵,'=',⍺⍵⍵⍵
, левый аргумент, за которым следует левый связанный аргумент, за которым следует правый аргумент, за которым=
следует правая функция (⍵⍵
), примененная к обоим аргументам. (Это функция форматированияX [configuration] Y [equals] (X [fn] Y)
.)⊃¨
: и затем распакуйте каждый элемент.{⍵,' =',⍵}¨⍵
: для каждого входного элемента⍵
настройте отдельные резисторы. (⍵
, ничего, ничего=
,⍵
).('+'+V⍵)
: используйтеV
функцию для создания всех последовательных конфигураций (символ есть'+'
и функция есть+
).'|'{÷+/÷⍺⍵}V⍵
: использоватьV
функцию для создания всех параллельных конфигураций (символ is'|'
и function is{÷+/÷⍺⍵}
, обратный сумме обратных аргументов).K←↑
: превратить это в матрицу и сохранить вK
.0 4↓K
: удалить 4 первых столбцаK
, оставив только значения сопротивления.|¯1+⍺÷⍨
: вычислить расстояние между⍺
каждой конфигурацией.K[⍋
...;]
: сортировкаK
по расстоянию.источник
510 code_here 100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700
⍎
), I / O (⎕
) или любые системные переменные (даже⎕UCS
и⎕A
не работают), поэтому большинство программ APL не будут работать. На самом деле он выдаст ОШИБКУ СИНТАКСА, если будет использована одна из отключенных функций. Тот факт, что эта функция не использует одну из многих функций, которые не поддерживает TryAPL, является совпадением.Python 3 -
250247270 байтЗапустите так:
(то есть список резисторов, разделенных пробелами, с целевым значением в конце)
Выход:
Я бы сказал, что вывод, скажем,Не было приемлемо Стоит мне байтов. Теперь я сортирую кортежи перед тем, как поместить их в набор, в противном случае решение идентично.680|2200
и2200|680
отдельно, все еще довольно ясен. Если это неприемлемо, я могу изменить это, но это будет стоить мне байтов.источник
import sys;r=sys.args[1:]
используйтеr=input().split()
и скажите, что вы должны указать значения в stdin. Наконец: вы используете1/sum(1/int(n)for n in b)
вместо1/sum(map(lambda n:1/int(n),b)
. В целом, это должно быть 274Ruby 2.1,
156154 байтаUngolfed:
Что оно делает:
e
вa
;a
, вычисляя одиночные, последовательные и параллельные значения как ключи к напечатанным значениям в хэшеc
;z
каждого ключа вc
; а также,e[1]
для каждого ключаe[0]
вc
распечатайтеe[1]=e[0]
.Пример использования:
s[[100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700], 510]
Пример вывода:
источник
JavaScript (ECMAScript 6) - 186 символов
Входные данные:
R
сопротивлений резисторов; а такжеT
Целевое сопротивление.Выход:
Массив массивов (отсортированный по расстоянию от
T
), каждый из которых содержит:p
,s
Или 0 , если резисторы соединены параллельно, последовательно или одиночные; а такжеОбъяснение:
источник
Юлия -
179163 байтаЭто работает так же, как и в старой версии, но аргумент в выражении print был организован несколько иначе, чтобы уменьшить количество необходимых квадратных скобок. Сохраняет 4 байта. Поглощение создания вектора пробелов в аргументе печати экономит лишние 2 байта. Он также перешел от использования «find» для получения соответствующих индексов к использованию логической формы. Сохраняет 6 байтов. Поглощение вычисления вектора индекса в корректировке A сэкономило еще 2 байта. Наконец, замена endof (v) на sum (v) позволила сохранить еще 2 байта. Общая экономия: 16 байт.
Старая версия:
Внутри функции вот что она делает:
Пример вывода:
источник
Javascript (E6) 156
162 164 186Последнее редактирование Предполагая, что все значения резисторов> 0, вы можете использовать их для контура
Использование :
F(510, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700])
Ungolfed
источник
Javascript, 248 байт
Использование :
r(510, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700]);
Выход
источник
Perl,
213199185 байт213 байтов:
199 байт:
185 байт:
Передайте все доступные резисторы в качестве аргументов. Целевое сопротивление должно быть последним:
Как это работает (старый код)
Определить подпрограммы
S
иP
вычислить сумму и параллельные значения двух резисторов.Установите
$"
в «,» для интерполяции@ARGV
внутриglob
оператора<{S,P}({@i},{@i})= S({@i})=>
генерирует декартово все возможности:S (100,100), S (100,150), S (100,220), ... P (100,100), P (100,150) ... S (100), S (150) ...
Объедините
s///ee
с,grep
чтобы оценить эквивалентные сопротивления и отфильтровать нежелательные повторы (в исполнении(??{$2<$3})
и/\d$/
sort
по фитнесу, вычисленному в подпрограммеt
Изменения в новом коде
Избегайте использования
s///ee
, используйте более короткое регулярное выражение с условной проверкой иeval
внутриgrep
Заменить повторы
"{@i}" with
$ i`Представьте
$x
,$y
вместо того$2
,$3
Заменить
split/=/,pop
на$_[0]=~s!!!r
Нет необходимости в трейлинге
;
eval;
эквивалентноeval $_;
Добавьте
=
вместе сeval
-ed ответ вместо того, чтобы объявить его заранееВыход:
P
представляет резисторы параллельно,S
представляет резисторы последовательно.источник
S(100)=100
иS(1000)=1000
.