laziness, impatience, and hubris PerlMonks

### Golf: overtone calculator

by Django (Pilgrim)
 on Sep 01, 2002 at 18:27 UTC ( #194468=perlmeditation: print w/ replies, xml ) Need Help??

Just another simple math challenge:
Write a subroutine that returns a list of all even harmonics (overtones) of a given frequency and their indirect harmonics up to a given factor.

arguments:
```    x: basic frequency (Hz)    (number  > 0)
n: maximum harmonic factor (integer > 0)

the returning list must be sorted (min .. max value) and each value (y) must be within the following range:
```      ( x <= y          )
&&(      y <= n * x )

The values must be unique and rounded to 3 digits after decimal point.

```=for Example:
sub Harmonics (\$\$) { ...add your code here... }
print join( "\n", Harmonics( 100, 6 ) );
# would print the following (without comments):
100.000  # 100 * 1/1
120.000  # 100 * 6/5
125.000  # 100 * 5/4
133.333  # 100 * 4/3
150.000  # 100 * 3/2
166.667  # 100 * 5/3
200.000  # 100 * 2/1
250.000  # 100 * 5/2
300.000  # 100 * 3/1
400.000  # 100 * 4/1
500.000  # 100 * 5/1
600.000  # 100 * 6/1
=cut

Here's my little program, with a subroutine of 81 chars and warnings enabled:

 ```#!usr/bin/perl -w sub Harmonics (\$\$) { for\$i(1..\$_[1]){for\$j(1..\$i){\$y{sprintf"%.3f",\$_[0]*\$i/\$j}=1}}sort{\$a< +=>\$b}keys%y } print join( "\n", Harmonics( 100, 6 ) ); [download]```

update: no trailing zero supression was intended (fixed the example).
Thanx to BrowserUK for looking closely.

~Django
"Why don't we ever challenge the spherical earth theory?"

Replies are listed 'Best First'.
Re: Golf: overtone calculator
by BrowserUk (Pope) on Sep 01, 2002 at 19:49 UTC

Yours unseen, this is scarily close, but I pipped you by 1!

```#! perl -w
sub H(\$\$){
map int(1e3*\$_[0]*\$_)/1e3,grep!\$^H{\$_}++,sort map{\$.=\$_;map\$./\$_,1..\$_
+}1..\$_[1]
}
\$"=\$/;print "@{[H(100,6)]}\n";
__END__
C:\test>194468
100
120
125
133.333
150
166.666
200
250
300
400
500
600

C:\test>

UpdateSlight improvement 77. Nowhere near jynx's, but ...both mine comply with the spec!

Neither yours nor Jynx's do! You showed trailing zero supression 8^). (That's my nose in the air:)

```sub H(\$\$){
map{int(1e3*\$_*\$_[0])/1e3}grep!\$_{\$_}++,sort map{\$.=\$_;map\$./\$_,1..\$_}
+1..pop
}

Well It's better than the Abottoire, but Yorkshire!

Trailing zero supression wasn't intended (fixed it).
Would you mind explaining your code? I'm just examining it for the nth time and still can't get no grip on it...

~Django
"Why don't we ever challenge the spherical earth theory?"

Is it so different from yours?

Nested map's -v- nested for's

Instead of using sprintf, I multiply the result by 1e3 int it and divide by 1e3 again.

Which bit gave you problem's?

BTW. I noted your comment re: jynx's and lexical sorting when n>10, and realise that mine suffers the same flaw. So, numerisising(is that a word?) the sort, I got

```#! perl -w
sub H(\$\$){
#________1_________2_________3_________4_________5_________6_________7
+_________8____
#234567890123456789012345678901234567890123456789012345678901234567890
+12345678901234
map{int(1e3*\$_*\$_[0])/1e3}grep!\$_{\$_}++,sort{\$a<=>\$b}map{\$.=\$_;map\$./\$
+_,1..\$_}1..pop
}

The extra 9 chars* cost me dear, and you were winning by 3, but I couldn't have that so...for a round of 76:

```sub H(\$\$){
#________1_________2_________3_________4_________5_________6_________7
+______
#234567890123456789012345678901234567890123456789012345678901234567890
+123456
map{\$.=\$_,map\$_{int(\$_[0]*1e3*\$./\$_)/1e3}++,1..\$_}1..pop;sort{\$a<=>\$b}
+keys%_
}

but that meant using a map in a void context so for the same 76, but avoiding that pesky map

```sub H(\$\$){
#________1_________2_________3_________4_________5_________6_________7
+______
#234567890123456789012345678901234567890123456789012345678901234567890
+123456
\$.=\$_,map\$_{int(\$_[0]*1e3*\$./\$_)/1e3}++,1..\$_ for 1..pop;sort{\$a<=>\$b}
+keys%_
}

By now the light was fading and it was hard to keep my eye on the ball, so bad light stopped play and the tournement can resume tomorrow with jynx first to step up to the tee:)

Update However, during floodlite play, (and stealing jynx's best bits), and retaining the more aesethically pleasing trailing zero suppression:), I give you this for 71

```sub H(\$\$){
#________1_________2_________3_________4_________5_________6_________7
+_
#234567890123456789012345678901234567890123456789012345678901234567890
+1
for\$.(1..pop){\$_{int(\$_[0]*1e3*\$./\$_)/1e3}++for 1..\$.}sort{\$a-\$b}keys%
+_
}

* I officially motion, on behalf of golfer's everywhere, that Perl6 have a sortn built-in that assumes the \$a<=>\$b. (Along with rev as an alias for reverse 8^).

Well It's better than the Abottoire, but Yorkshire!
Re: Golf: overtone calculator
by jynx (Priest) on Sep 01, 2002 at 19:15 UTC

just quickly,

Here's a slightly shorter version that still compiles under strict and warnings. i only have tested it under the single test case above, if it fails others please provide them and i'll try to correct it. Anyway, this weighs in at 66 characters:

```sub Harmonics (\$\$) {
#23456789_123456789_123456789_123456789_123456789_123456789_123456789_
for\$a(1..pop){\$_{sprintf'%.3f',\$_[0]*\$a/\$_}++for 1..\$a}sort keys%_
}
jynx

Impressing inner loop, but your sort will fail with \$_[1] > 10, because it sorts lexically.

~Django
"Why don't we ever challenge the spherical earth theory?"

Does this fix the problem? (at 72 chars):
```sub Harmonics (\$\$) {
#23456789_123456789_123456789_123456789_123456789_123456789_123456789_
+12
for\$a(1..pop){\$_{sprintf'%.3f',\$_[0]*\$a/\$_}++for 1..\$a}sort{\$a-\$b}keys
+%_
}
jynx
Re: Golf: overtone calculator
by Aristotle (Chancellor) on Sep 02, 2002 at 02:01 UTC
Not a very golfable task. It is practically chosen such that the algorithm cannot be varied, and picking a better algorithm is what golf is really about. Not surprisingly my best entry is a variation on the initial attempt. Alternative approaches were only longer.
```#        1         2         3         4         5         6         7
+         8
#234567890123456789012345678901234567890123456789012345678901234567890
+1234567890
for\$a(1..pop){@_{map{sprintf"%.3f",\$_[0]*\$a/\$_}1..\$a}++}sort{\$a<=>\$b}k
+eys%_

grep!\$_{\$_}++,sort{\$a<=>\$b}map{\$a=\$_;map{sprintf"%.3f",\$_[0]*\$a/\$_}1..
+\$_}1..pop

my%y=map{\$_=>[1..\$_]}1..pop;@_{map{sprintf"%.3f",\$_[0]*\$a/\$_}@\$b}++whi
+le(\$a,\$b)=each%y;sort{\$a<=>\$b}keys%_

Makeshifts last the longest.

Re: Golf: overtone calculator
by tadman (Prior) on Sep 02, 2002 at 09:04 UTC
Here's my retooling of BrowserUk/Arien's solution, which falls one character shy of matching:
sort{\$a-\$b}keys%{{map{map{1e-3*int"@_"*1e3*\$x/\$_,0}1..(\$x=\$_)}1..pop}}
It had promise, I swear! I was sure that the old "keys on temporary hash" trick would work, but alas, denied. I futzed with the clever sprintf() replacement, and could not find any slack. Very elegant.

By the way, I just have to interject that Perl 5 prototypes are evil. I'd suggest not using them.

Update: Added missing bracket per Django's catch.

Little optimization:

sort{\$a-\$b}keys%{{map{map{1e-3*int"@_.e3"*\$'/\$_,0}/^/..\$_}1..pop}}

There's a closing curly missing at the end. Apart from that: elegant indeed!

Why do you consider Perl 5 prototypes as evil? I like the ability to use subs like built-ins.

~Django
"Why don't we ever challenge the spherical earth theory?"

They are poison. You should only use them when you have to, like forcing an array or subroutine reference. Here's two typical examples:
```sub my_grep(&) { ... }
sub my_pop(\@) { ... }
Putting in scalars (i.e. (\$\$)) is asking for trouble since it converts any arrays to scalars automatically. I found this really quite worrying, and you can see my brief rant in Function Prototypes and Array vs. List (Pt. 2).

This all comes from a technique of jamming arrays into functions, which I do all the time to be efficient. Things like this:
```my \$sth = \$dbh->prepare("SELECT id,name,age FROM foo");
\$sth->execute();

while (my \$row = \$sth->fetchrow())
{
\$self->some_function(@\$row);
}
Now, if you've prototyped your function, you're going to get the number 3 every time. This is put in to the 'id' field, so you might actually think it's valid data, too.

Instead, just leave those things off. That's why merlyn says "...and this is why we tell people DO NOT USE PROTOTYPES".

Create A New User
Node Status?
node history
Node Type: perlmeditation [id://194468]
Approved by TStanley
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (7)
As of 2016-07-28 06:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
What is your favorite alternate name for a (specific) keyboard key?

Results (253 votes). Check out past polls.