| Bytes | Lang | Time | Link |
|---|---|---|---|
| 068 | APLNARS | 250908T045520Z | Rosario |
| 119 | Janet | 250907T142856Z | Adam |
| 185 | Perl | 140528T113009Z | Zaid |
| 163 | Julia 179 | 140526T162516Z | Glen O |
| 070 | J | 140526T140100Z | algorith |
| nan | 140526T110852Z | edc65 | |
| 186 | JavaScript ECMAScript 6 186 Characters | 140526T125734Z | MT0 |
| nan | Ruby 2.1 | 140526T083205Z | josh |
| 248 | Javascript | 140526T062838Z | Snack |
| 270 | Python 3 250 247 | 140526T013618Z | undergro |
| 102 | APL | 140526T011113Z | marinus |
| 122 | Mathematica | 140525T235631Z | Martin E |
APL(NARS), 68 chars
{⊃k[⍋∣⍟⍺÷⍨¨↑¨k←⍵∪((÷+/∘÷¨k),¨'∣',¨k)∪(+/¨k),¨'+',¨k←k/⍨≤/¨k←,∘.,⍨⍵]}
The input is in the left one number ⍺ that represent the value to approximate, in the right ⍵ a list of numbers that represent the resistors values.
Because that use "⍟⍺÷⍨" in the list ⍵ each element has to be >0 and ⍺>0 (because there is the log_base_e ⍟ and ÷).
The output list is composed I column the result, or the value if it is a single resistor too, in II column | for resistors in parallel, + for resistors in series, 0 for a single resistor, III and IV columns the values from ⍵ list if case of resistor in parallel (|) or series (+) or 0 if it is a single resistor.
test:
R←{⊃k[⍋∣⍟⍺÷⍨¨↑¨k←⍵∪((÷+/∘÷¨k),¨'∣',¨k)∪(+/¨k),¨'+',¨k←k/⍨≤/¨k←,∘.,⍨⍵]}
510 R 100 150 220 330 470 680 1000 1500 2200 3300 4700
519.4444444 ∣ 680 2200
500 ∣ 1000 1000
480 + 150 330
550 + 220 330
470 0 0 0
467.8899083 ∣ 680 1500
563.8190955 ∣ 680 3300
570 + 100 470
440 + 220 220
594.0520446 ∣ 680 4700
600 ∣ 1000 1500
430 + 100 330
427.2727273 ∣ 470 4700
620 + 150 470
..........
6200 + 1500 4700
6600 + 3300 3300
6900 + 2200 4700
8000 + 3300 4700
9400 + 4700 4700
≢510 R 100 150 220 330 470 680 1000 1500 2200 3300 4700
143
Janet, 119 bytes
(fn[a t](sort-by|(math/abs(-(/($ 3)t)1))(catseq[r :in a s :in a](if(> r s)[][[r'+ s(+ r s)][r'& s(/(+(/ r)(/ s)))]]))))
A function that takes a list of available resistors a and a target resistance t and outputs an array like this:
@[(680 & 2200 519.444444444444) (1000 & 1000 500) (150 + 330 480) … (4700 + 4700 9400)]
Perl, 213 199 185 bytes
213 bytes:
$t=pop;sub t{abs 1-(split/=/,pop)[1]/$t}sub S{$_[0]+$_[1]}sub P{$_[0]*$_[1]/&S}$"=',';@i=@ARGV;say for sort{t($a)<=>t($b)}grep s!(..\b(\d+)\b,?\b(\d+)?\b\))=\K(??{$2<$3})!$1!ee&&/\d$/,<{S,P}({@i},{@i})= S({@i})=>;
199 bytes:
$t=pop;sub t{abs 1-(split/=/,pop)[1]/$t}sub S{$_[0]+$_[1]}sub P{$_[0]*$_[1]/&S}$"=',';@i=@ARGV;say for sort{t($a)<=>t($b)}grep/(..(\d+),?(\d+)?\))/&&$2>=$3&&($_.=eval$1),<{S,P}({@i},{@i})= S({@i})=>;
185 bytes:
$t=pop;sub t{abs 1-$_[0]=~s!.*=!!r/$t}sub S{$_[0]+$_[1]}sub P{$_[0]*$_[1]/&S}$"=',';$i="{@ARGV}";say for sort{t($a)<=>t$b}grep{my($x,$y)=/\d+/g;$_.='='.eval,$x>=$y}<{S,P}($i,$i) S($i)>
Pass all available resistors as arguments. The target resistance should be the last:
$ perl -E 'code' R1 R2 R3 ... Rn target
How it works (old code)
Define subroutines
SandPto compute the sum and parallel values of two resistors.<{S,P}({@i},{@i})= S({@i})=>generates a cartesian of all possibilities:S(100,100), S(100,150), S(100,220), ... P(100,100), P(100,150) ... S(100), S(150) ...
Combine
s///eewithgrepto evaluate the equivalent resistances and filter out unwanted repeats (performed by(??{$2<$3})and/\d$/sortby fitness computed in subroutinet
Changes in new code
Avoid use of
s///ee, use shorter regex with conditional checking andevalinsidegrepReplace repeats of
"{@i}" with$i`Introduce
$x,$yinstead of$2,$3Replace
split/=/,popwith$_[0]=~s!!!rNo need for trailing
;eval;is equivalent toeval $_;Add
=along witheval-ed answer instead of declaring it up front
Output:
P represents resistors in parallel, S represents resistors in series.
P(2200,680)=519.444444444444
P(1000,1000)=500
S(330,150)=480
S(330,220)=550
S(470)=470
P(1500,680)=467.889908256881
P(3300,680)=563.819095477387
S(470,100)=570
S(220,220)=440
S(330,100)=430
P(4700,470)=427.272727272727
P(4700,680)=594.052044609665
P(1500,1000)=600
P(3300,470)=411.405835543767
P(1000,680)=404.761904761905
S(470,150)=620
P(2200,470)=387.265917602996
S(220,150)=370
S(330,330)=660
P(1500,470)=357.868020304569
S(680)=680
P(680,680)=340
P(2200,1000)=687.5
S(330)=330
S(470,220)=690
S(220,100)=320
P(1000,470)=319.727891156463
P(4700,330)=308.349900596421
S(150,150)=300
P(3300,330)=300
P(2200,330)=286.95652173913
P(680,470)=277.913043478261
P(1500,330)=270.491803278689
P(1500,1500)=750
P(3300,1000)=767.441860465116
S(150,100)=250
P(1000,330)=248.12030075188
S(680,100)=780
P(470,470)=235
P(680,330)=222.178217821782
S(470,330)=800
S(220)=220
P(4700,220)=210.162601626016
P(3300,220)=206.25
S(100,100)=200
P(2200,220)=200
P(4700,1000)=824.561403508772
P(470,330)=193.875
P(1500,220)=191.860465116279
S(680,150)=830
P(1000,220)=180.327868852459
P(680,220)=166.222222222222
P(330,330)=165
S(150)=150
P(470,220)=149.855072463768
P(4700,150)=145.360824742268
P(3300,150)=143.478260869565
P(2200,150)=140.425531914894
P(1500,150)=136.363636363636
P(330,220)=132
P(1000,150)=130.434782608696
P(2200,1500)=891.891891891892
P(680,150)=122.89156626506
S(680,220)=900
P(470,150)=113.709677419355
P(220,220)=110
P(330,150)=103.125
S(100)=100
P(4700,100)=97.9166666666667
P(3300,100)=97.0588235294118
P(2200,100)=95.6521739130435
P(1500,100)=93.75
P(1000,100)=90.9090909090909
P(220,150)=89.1891891891892
P(680,100)=87.1794871794872
P(470,100)=82.4561403508772
S(470,470)=940
P(330,100)=76.7441860465116
P(150,150)=75
P(220,100)=68.75
P(150,100)=60
P(100,100)=50
S(1000)=1000
S(680,330)=1010
P(3300,1500)=1031.25
S(1000,100)=1100
P(2200,2200)=1100
P(4700,1500)=1137.09677419355
S(680,470)=1150
S(1000,150)=1150
S(1000,220)=1220
P(3300,2200)=1320
S(1000,330)=1330
S(680,680)=1360
S(1000,470)=1470
P(4700,2200)=1498.55072463768
S(1500)=1500
S(1500,100)=1600
S(1500,150)=1650
P(3300,3300)=1650
S(1000,680)=1680
S(1500,220)=1720
S(1500,330)=1830
P(4700,3300)=1938.75
S(1500,470)=1970
S(1000,1000)=2000
S(1500,680)=2180
S(2200)=2200
S(2200,100)=2300
S(2200,150)=2350
P(4700,4700)=2350
S(2200,220)=2420
S(1500,1000)=2500
S(2200,330)=2530
S(2200,470)=2670
S(2200,680)=2880
S(1500,1500)=3000
S(2200,1000)=3200
S(3300)=3300
S(3300,100)=3400
S(3300,150)=3450
S(3300,220)=3520
S(3300,330)=3630
S(2200,1500)=3700
S(3300,470)=3770
S(3300,680)=3980
S(3300,1000)=4300
S(2200,2200)=4400
S(4700)=4700
S(3300,1500)=4800
S(4700,100)=4800
S(4700,150)=4850
S(4700,220)=4920
S(4700,330)=5030
S(4700,470)=5170
S(4700,680)=5380
S(3300,2200)=5500
S(4700,1000)=5700
S(4700,1500)=6200
S(3300,3300)=6600
S(4700,2200)=6900
S(4700,3300)=8000
S(4700,4700)=9400
Julia - 179 163 bytes
f(t,s)=(\ =repmat;m=endof(s);A=A[v=(A=s\m).>=(B=sort(A))];B=B[v];F=[s,C=A+B,A.*B./C];n=sum(v);print([[s P=[" "]\m P;A [+]\n B;A [|]\n B] F][sortperm(abs(F-t)),:]))
This works the same as the old version, but the argument in the print statement has been organised slightly differently to reduce the number of square brackets necessary. Saves 4 bytes. Absorbing the spaces vector creation into the print argument saves an extra 2 bytes. It has also switched from using "find" to get the relevant indices to using the logical form. Saves 6 bytes. Absorbing the calculation of the index vector into the adjustment of A saved another 2 bytes. Finally, replacing endof(v) with sum(v) saved 2 more bytes. Total saving: 16 bytes.
Old version:
f(t,s)=(\ =repmat;m=endof(s);A=s\m;v=find(A.>=(B=sort(A)));A=A[v];B=B[v];F=[s,C=A+B,A.*B./C];n=endof(v);P=[" "]\m;print([[s,A,A] [P,[+]\n,[|]\n] [P,B,B] F][sortperm(abs(F-t)),:]))
Within the function, here's what it's doing:
\ =repmat # Overloads \ operator to save lots of characters
m=endof(s) # Length of input s ("Stock")
A=s\m # Equivalent to repmat(s,m) (see first command)
B=sort(A) # Same as A but sorted - rather than cycling through
# the resistors m times, it repeats each one m times
v=find(A.>=B) # Identify which pairs for A,B have A>=B
A=A[v];B=B[v] # Remove pairs where A<B (prevents duplicates)
F=[s,C=A+B,A.*B./C] # Constructs vector containing results for single resistor,
# resistors in series, and resistors in parallel
n=endof(v) # equivalent to n=(m+1)m/2, gets number of relevant pairs
P=[" "]\m # Construct array of blank entries for use in constructing output
print([[s,A,A] [P,[+]\n,[|]\n] [P,B,B] F][sortperm(abs(F-t)),:]))
# The following are the components of the argument in the print statement:
[s,A,A] # Set of resistor values for resistor 1
[P,[+]\n,[|]\n] # Operator column, prints either nothing, +, or |
[P,B,B] # Set of resistor values for resistor 2 (blank for single resistor)
F # Contains resulting equivalent resistance
[sortperm(abs(F-t)),:] # Determines permutation for sorting array by distance from Target t
# and applies it to array
Sample output:
julia> f(170,[100,220,300])
300 | 300 150
100 + 100 200
300 | 220 126.92307692307692
220 220
220 | 220 110
100 100
300 | 100 75
220 | 100 68.75
100 | 100 50
300 300
220 + 100 320
300 + 100 400
220 + 220 440
300 + 220 520
300 + 300 600
J - 86 71 70 char
((]/:[|@<:@%~2{::"1])(;a:,<)"0,[:,/(<,.+`|,.+/;+&.%/)"1@;@((<@,.{:)\))
I'm not going to bother to explain every little detail because a lot of the code is spent syncing up the results of different functions, but here's the gist of the golf:
;@((<@,.{:)\)makes every possible pair of resistors, to be connected either in parallel or in series.[:,/(<,.+`|,.+/;+&.%/)"1@then connects them, in parallel and in series, making a big list of possible connections.(;a:,<)"0,adds in the possibility of using only one resistor by itself to approximate.(]/:[|@<:@%~2{::"1])sorts the list of combinations of resistors by the pseudolog distance (|@<:@%) between the target and the resultant resistance from each combination.
And this is how to use it:
rouv =: ((]/:[|@<:@%~2{::"1])(;a:,<)"0,[:,/(<,.+`|,.+/;+&.%/)"1@;@((<@,.{:)\))
# 510 rouv 100 150 220 330 470 680 1000 1500 2200 3300 4700 NB. how many?
143
10 {. 510 rouv 100 150 220 330 470 680 1000 1500 2200 3300 4700 NB. view first 10
+---------+-+-------+
|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 |
+---------+-+-------+
You don't have to only view the first 10 like I did above, but this is a function and the J REPL truncates very large return values, and the full output for this example has 287 lines. You can force it all to STDOUT with something like tmoutput toCRLF , LF ,.~ ": blah rouv blah on Windows—drop the toCRLF on Linux—but rouv is a function and internally, all the rows exist.
Note:
The question seems to have been changed right under our noses, and now the log distance is defined as abs(log(Rapprox/Rtarget)) instead of abs(Rapprox/Rtarget-1). To correct this in my golf, we can change the |@<:@% to |@^.@%: <: is Decrement while ^. is Logarithm.
Javascript (E6) 156 162 164 186
Last Edit Assuming all resistor values > 0, you can use them for the loop condition
F=(t,s)=>{D=a=>Math.abs(a[1]/t-1);for(i=r=[];a=s[j=i++];r[l]=[a,a])for(;b=s[j--];)l=r.push([a+'+'+b,c=a+b],[a+'|'+b,a*b/c]);return r.sort((a,b)=>D(a)-D(b))}
Usage : F(510, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700])
Ungolfed
F = (t,s) =>
{
D = a => Math.abs(a[1]/t-1);
for (i=r=[]; a=s[j=i++]; r[l]=[a,a])
for(; b=s[j--];)
l = r.push([a+'+'+b, c=a+b], [a+'|'+b, a*b/c]);
return r.sort((a,b) => D(a)-D(b))
}
JavaScript (ECMAScript 6) - 186 Characters
f=(R,T)=>(D=x=>Math.abs(x[3]/T-1),r={p:(x,y)=>x*y/(x+y),s:(x,y)=>x+y},[...[[x,0,0,x]for(x of R)],...[[x,y,z,r[z](x,y)]for(x of R)for(y of R)for(z in r)if(x<=y)]].sort((a,b)=>D(a)-D(b)))
Input:
- An array
Rof resistor strengths; and T, the target resistance.
Output:
An array of arrays (sorted by distance from T) each containing:
- the smaller resistor's value;
- the higher resistor's value (or 0 if a solitary resistor);
p,sor 0 if the resistors are in parallel, serial or solitary; and- the net resistance.
Explanation:
f=(R,T)=>( // Create a function f with arguments R & T
D=x=>Math.abs(x[3]/T-1), // A function D to calculate relative
// distance from the target value
r={p:(x,y)=>x*y/(x+y),s:(x,y)=>x+y}, // An object containing the formulae
// to calculate resistance in serial and parallel
solitary = [[x,0,0,x]for(x of R)], // Create an array of solitary resistors
pairs = // Use Array Comprehension to create the array of
[[x,y,z,r[z](x,y)] // arrays
for(x of R) // for each resistor value
for(y of R) // for each resistor value (again)
for(z in r) // for both serial & parallel
if(x<=y)], // where the first resistor value is smaller than the second
[
...solitary, // Use the spread ... operator to combine
...pairs // the two arrays
]
.sort((a,b)=>D(a)-D(b)) // Sort the arrays by minimum distance
// and return.
)
Ruby 2.1, 156 154 bytes
s=->(a,z){c={};a.map{|e|a.map{|f|c[e]=e;c[e+f]="#{e}+#{f}";c[1/(1.0/f+1.0/e)]="#{e}|#{f}"}};c.sort_by{|k,|(k/z.to_f-1).abs}.map{|e|puts"#{e[1]}=#{e[0]}"}}
Ungolfed:
s =->(a,z) {
c={}
a.map{|e|
a.map{|f|
c[e]=e
c[e+f]="#{e}+#{f}"
c[1/(1.0/f+1.0/e)]="#{e}|#{f}"
}
}
c.sort_by{|k,|
(k/z.to_f-1).abs
}.map{|e|
puts "#{e[1]}=#{e[0]}"
}
}
What it does:
- For each value
eina;- Iterate through
a, computing single, series, and parallel values as keys to printed values in hashc;
- Iterate through
- Determine distance from
zfor each key inc; and, - For each value
e[1]for each keye[0]inc, printe[1]=e[0].
Sample usage:
s[[100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700], 510]
Sample output:
2200|680=519.4444444444445
1000|1000=500.0
330+150=480
330+220=550
470=470
1500|680=467.88990825688074
3300|680=563.8190954773869
.
.
.
4700+1500=6200
3300+3300=6600
4700+2200=6900
4700+3300=8000
4700+4700=9400
Javascript, 248 bytes
function r(T,L){R=[],O="";for(i in L){R.push([a=L[i],a]);for(j=i;j<L.length;)b=L[j++],s=a+b,R.push([a+"+"+b,s],[a+"|"+b,a*b/s])}R.sort(function(a,b){A=Math.abs;return A(a[1]/T-1)-A(b[1]/T-1)});for(i in R)q=R[i],O+=q[0]+"="+q[1]+"\n";console.log(O)}
Usage : r(510, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700]);
Output
670|2200=519.4444444444445
1000|1000=500
150+330=480
(...such rows...)
2200+4700=6900
3300+4700=8000
4700+4700=9400
Python 3 - 250 247 270 bytes
from itertools import*
import sys
r=sys.argv[1:]
t=int(r.pop())
p=set(map(tuple,map(sorted,product(r,r))))
a=[('+'.join(b),sum(map(int,b)))for b in p]+[('|'.join(b),1/sum(map(lambda n:1/int(n),b)))for b in p]
for s in sorted(a,key=lambda b:abs(float(b[1])/t-1)):print(s)
Run like this:
python resistors.py 100 150 220 330 470 680 1000 1500 2200 3300 4700 510
(that is, a space-delimited list of resistors, with the target value at the end)
Output:
('2200|680', 519.4444444444445)
('1000|1000', 500.0)
('150+330', 480)
('220+330', 550)
('1500|680', 467.88990825688074)
('3300|680', 563.8190954773869)
[snip]
('2200+4700', 6900)
('3300+4700', 8000)
('4700+4700', 9400)
I would say that outputting, say, Wasn't acceptable. Cost me bytes. Now I sort the tuples before chucking them into the set, otherwise the solution is identical.680|2200 and 2200|680 separately is still pretty clear. If this is unacceptable, I can change it, but it'll cost me bytes.
APL (102)
{V←{⊃¨⍺{⍺,⍺⍺,⍵,'=',⍺⍵⍵⍵}⍺⍺/¨Z/⍨≤/¨Z←,∘.,⍨⍵}⋄K[⍋|¯1+⍺÷⍨0 4↓K←↑('|'{÷+/÷⍺⍵}V⍵),('+'+V⍵),{⍵,' =',⍵}¨⍵;]}
This takes the target resistance as the left argument and a list of available resistors as the right argument.
Explanation:
V←{...}:Vis a function that:Z/⍨≤/¨Z←,∘.,⍨⍵: finds every unique combination of two values in⍵,Z←,∘.,⍨⍵: join each value in⍵with each value in⍵, store inZ,Z/⍨≤/¨Z: select fromZthose combinations where the first value is less than or equal to the second value
⍺{...}⍺⍺/¨: and then applies following function, bound with the left function (⍺⍺) on the right and the left argument (⍺) on the left, to each pair:⍺,⍺⍺,⍵,'=',⍺⍵⍵⍵, the left argument, followed by the left bound argument, followed by the right argument, followed by=, followed by the right function (⍵⍵) applied to both arguments. (This is the formatting function,X [configuration] Y [equals] (X [fn] Y).)
⊃¨: and then unbox each element.
{⍵,' =',⍵}¨⍵: for each element in⍵, make the configurations for the individual resistors. (⍵, nothing, nothing,=,⍵).('+'+V⍵): use theVfunction to make all serial configurations (character is'+'and function is+).'|'{÷+/÷⍺⍵}V⍵: use theVfunction to make all parallel configurations (character is'|'and function is{÷+/÷⍺⍵}, inverse of sum of inverse of arguments).K←↑: make this into a matrix and store it inK.0 4↓K: drop the 4 first columns fromK, leaving only the resistance values.|¯1+⍺÷⍨: calculate the distance between⍺and each configuration.K[⍋...;]: sortKby the distances.
Mathematica, 151 122 characters
Expects the target resistance to be stored in r and the list of available resistors in l.
SortBy[Join[{#,#}&/@l,Join@@(#@@@Union[Sort/@N@l~Tuples~{2}]&/@{{"+",##,#+#2}&,{"|",##,#*#2/(#+#2)}&})],Abs[#[[-1]]/r-1]&]
Less golf:
SortBy[Join[{#, #} & /@ l,
Join @@ (# @@@
Union[Sort /@ N@l~Tuples~{2}] & /@ {{"+", ##, # + #2} &, {"|", ##,
#*#2/(# + #2)} &})], Abs[#[[-1]]/r - 1] &]
The output format differs from the suggested one but configurations are easily determinable. The output is a list of configurations. Each configuration is of one of the following forms:
{R1, Total}
{"+", R1, R2, Total}
{"|", R1, R2, Total}
So the first three elements of the output read
{{"|", 680., 2200., 519.444}, {"|", 1000., 1000., 500.}, {"+", 150., 330., 480.}, ...}
If you're fine with rational numbers, I could save two characters from omitting N@. That is, the first element (for instance) would be returned as 4675/9 instead of 519.444.