19
\$\begingroup\$

Create a program that computes the hamming weight of a string. Winner is the program with the lowest hamming weight.

Rules:

  • Hamming weight for an ASCII character is defined as the total number of bits set to 1 in its binary representation.
  • Assume input encoding is 7-bit ASCII, passed through whatever input mechanism is normal for your language (e.g. stdin, args, etc.)
  • Output the result, as a number, to stdout or whatever default/normal output mechanism your language uses.
  • It should go without saying, but you have to be able to actually run the program, in real life, for it to be a valid solution.
  • Winner is the solution whose code has the lowest hamming weight.
  • Sorry, no solutions in whitespace for this one! Ok, you can code in whitespace now I've sorted out the rules :)

Per-character examples:

char |  binary  | weight
-----+----------+-------
a    | 01100001 | 3
x    | 01111000 | 4
?    | 00111111 | 6
\x00 | 00000000 | 0
\x7F | 01111111 | 7
\$\endgroup\$
11
  • \$\begingroup\$ if we take 0x20/ASCII 32 as the reference, isn't the humming weight of hello world 10 rather than 11? \$\endgroup\$ Commented Jun 7, 2012 at 13:11
  • \$\begingroup\$ Why is the weight of hello world 11? Only 10 characters are different from a space. Also - a program's Hamming weight seems to be just its length, excluding spaces. Not so different from normal code golf. \$\endgroup\$
    – ugoren
    Commented Jun 7, 2012 at 13:12
  • \$\begingroup\$ Sorry, I totally screwed this up. Wikipedia's hamming weight article is rather misleading, and I totally fubar'ed the rules. Re-writing now. Update: Ok, re-written to define it as the number of bits set to 1 in the ASCII string, sorry for the screw-up. \$\endgroup\$
    – Polynomial
    Commented Jun 7, 2012 at 13:16
  • \$\begingroup\$ @ugoren A solution with lower-value ASCII characters has a lower hamming weight. \$\endgroup\$
    – Polynomial
    Commented Jun 7, 2012 at 13:18
  • 1
    \$\begingroup\$ Now it all makes sense. USE UPPERCASE, BEWARE OF ~ AND o. \$\endgroup\$
    – ugoren
    Commented Jun 7, 2012 at 13:22

19 Answers 19

8
\$\begingroup\$

J, weight 34

+/,#:a.i.

Usage - place the string to be measured in quotes at the end:

   +/,#:a.i.'+/,#:a.i.'
34

Alternatively, taking input from the keyboard (weight 54):

   +/,#:a.i.1!:1[1
hello
21
\$\endgroup\$
3
  • \$\begingroup\$ There's only one way to write this :) \$\endgroup\$
    – ephemient
    Commented Jun 7, 2012 at 14:22
  • \$\begingroup\$ There isn't... I found a solution that has a hamming weight of one lower. \$\endgroup\$ Commented Jun 23, 2014 at 6:33
  • \$\begingroup\$ Not trying to be a buzzkill, but the rules ask for a program, not a fragment. \$\endgroup\$
    – FUZxxl
    Commented Jun 23, 2015 at 10:39
6
\$\begingroup\$

J (33)

One lower than 34!

+/,#:3 u:

Heavily inspired by this answer, but a hamming weight of one lower.

   +/,#:3 u:'+/,#:3 u:'
33
\$\endgroup\$
5
\$\begingroup\$

J, 39

+/,#:a.i:]

This is a function taking one argument. (Or replace ] with the string directly; as Gareth notes, that brings the cost down to 34.)

   +/,#:a.i:] 'hello world'
45
   +/,#:a.i:] '+/,#:a.i:]'
39
\$\endgroup\$
1
  • \$\begingroup\$ Great minds think alike. :-) \$\endgroup\$
    – Gareth
    Commented Jun 7, 2012 at 14:20
5
\$\begingroup\$

Python, 189

print sum(bin(ord(A)).count("1")for A in raw_input())
\$\endgroup\$
2
  • 2
    \$\begingroup\$ The Python 3 equivalent, print(sum(bin(ord(A)).count('1')for A in input())), has a score of 180. \$\endgroup\$
    – dan04
    Commented Jun 8, 2012 at 3:42
  • 4
    \$\begingroup\$ @dan04: Use double quotes instead of single for 176. \$\endgroup\$ Commented Jun 8, 2012 at 3:56
5
\$\begingroup\$

QBasic, 322 311 286 264

H$=COMMAND$
FOR A=1 TO LEN(H$)
B=ASC(MID$(H$,A,1))
WHILE B>0
D=D+B MOD 2
B=B\2
WEND
NEXT
?D

Kind of the right tool for the job, still sucks of course.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ +1 for using one of my favourite languages of all time. It's the first language I learnt to code in on a PC. \$\endgroup\$
    – Polynomial
    Commented Jun 7, 2012 at 20:09
5
\$\begingroup\$

Unary 0

You all knew it was coming. First the BrainFuck program:

,[[>++[>>+>+<<<-]>>>
[<<<+>>>-]>>[-]<<<<<<[>>>>+>>+<<<<<<-]>>>>>>
[<<<<<<+>>>>>>-]<<<[>>+>+<<<-]>>>[<<<+>>>-]
[-]<<[>>[-]<[>[-]+<[-]]<[-]]>[-]>[<<<<<<->>>->>>
[-]<<<<<<[>>>>+>>+<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]<<<
[>>+>+<<<-]>>>[<<<+>>>-][-]<<[>>[-]<[>[-]+<[-]]<[-]]>[-]>]<<<<<<
[>>+<[>>+>+<<<-]>>>[<<<+>>>-]>>[-]<<<<<<[>>>>+>>+<<<<<<-]>>>>>>
[<<<<<<+>>>>>>-]<<<[>>+>+<<<-]>>>[<<<+>>>-][-]<<[>>[-]<[>[-]+<[-]]<[-]]> 
[-]>[<<<<<<->>>->>>[-]<<<<<<[>>>>+>>+<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]<<<
[>>+>+<<<-]>>>[<<<+>>>-][-]<<[>>[-]<[>[-]+<[-]]<[-]]>[-]>]<<<<<<]>>>
[>+>+<<-]>>[<<+>>-][-]+<[>[-]<<[<<->>-]<<[>>+<<-]>>>[-]]>[<<<+<[-]>>>>
[-]]<<[->>>>+<<<<]<[-<<+>>]<<],]>>>>>>>.

I added newlines to make it "readable" but it has a Hamming weight of 4066. It works by repeatedly getting the quotient/remainders of an input string and adding up all the remainders. Of course should you run it on itself you get: 226 (4066 % 256) (technically \xe2) so clearly it rules itself the winner.

Now we convert it to Unary and get

000 ... 9*google^5.9 0's ... 000

We use a unary implementation with NULL characters \x00 for '0' and boom, hamming weight of 0.

Bonus question: For what ASCII characters c can you run this program on a string consisting on N repitions and have it output that character. (E.G. a string of 32 spaces gives a space). What values of N work (either an infinite number of them will work, or none will).

\$\endgroup\$
6
  • 1
    \$\begingroup\$ I'm not sure I understand this solution. The brainfuck program has a huge hamming weight. Does Unary accept null bytes as a program, or would you need to re-implement Unary? If it's the latter, it's not really a valid solution - anyone could just say "I define a programming language where any single input byte gives {result}", and win every code golf challenge on the site. \$\endgroup\$
    – Polynomial
    Commented Jun 8, 2012 at 10:08
  • 1
    \$\begingroup\$ A null character Unary would be fine. All you need is an EOF to say stop counting. In fact here's some pseudo-C to read that file: main(){ bignum Unarynum = 0; int c; while(EOF!=(c=readchar())){ Unarynum++; } return Unarynum; } Doesn't matter at all what you choose to be your Unary char (as long as it isn't EOF). \$\endgroup\$
    – walpen
    Commented Jun 8, 2012 at 12:02
  • 1
    \$\begingroup\$ Well here's a unary to C compiler that works fine with null characters: ideone.com/MIvAg. Of course the file required to make this program would not fit in the universe, but we have the capacity to run it. \$\endgroup\$
    – walpen
    Commented Jun 8, 2012 at 12:30
  • 3
    \$\begingroup\$ If you can't actually run it, it's not really a solution. \$\endgroup\$
    – Polynomial
    Commented Jun 8, 2012 at 12:33
  • 4
    \$\begingroup\$ As Carl Sagan once said: "If you wish to calculate the hamming weight of a string, you must first invent 10^500 universes." (billions and billions, even) \$\endgroup\$
    – walpen
    Commented Jun 8, 2012 at 23:13
4
\$\begingroup\$

C, weight 322 263 256

Does the hamming weight of the hamming weight count?

main(D,H,A)char*A,**H;{for(A=*++H;*A;A+=!(*A/=2))D+=*A%2;printf("%d",D-2);}

Used mostly standard golfing techniques.
A single loop calculates weight (shifting right and adding until zero) and scans the string (advances pointer when zero reached).
Assuming D is initialized to 2 (single parameter).

Hamming weight specific optimizations:
1. ABDH, with weight 2 each, used for names.
2. *++H preferred over H[1].

\$\endgroup\$
5
  • \$\begingroup\$ Hah, I utterly failed to understand your first sentence until just now. \$\endgroup\$
    – breadbox
    Commented Jun 8, 2012 at 3:35
  • \$\begingroup\$ You can get the score down to 230 by outputting the result as an unary number: main(D,H,A)char*A,**H;{for(A=*++H;*A;A+=!(*A/=2))if(*A%2)printf("@");} \$\endgroup\$
    – schnaader
    Commented Jun 9, 2012 at 0:29
  • \$\begingroup\$ @schnaader, I never knew @ was a digit in the unary system. I thought it only uses 0..0. But if you want to go this, way, printf("@"+*a%2) is shorter. \$\endgroup\$
    – ugoren
    Commented Jun 10, 2012 at 6:19
  • \$\begingroup\$ @ugoren: Depends on the convention/definition of unary. E.g. en.wikipedia.org/wiki/Unary_numeral_system does use tally marks and says "There is no explicit symbol representing zero in unary as there is in other traditional bases". \$\endgroup\$
    – schnaader
    Commented Jun 10, 2012 at 9:54
  • \$\begingroup\$ @schnaader, OK, but I think it's stretching the requirement "as a number" too far. \$\endgroup\$
    – ugoren
    Commented Jun 10, 2012 at 10:11
4
\$\begingroup\$

Golfscript 84 72 58

{2base~}%{+}*

(thanks to Howard and Peter Taylor for their help)

Input: the input string has to be on the stack (passed as command line argument, or simply placed on the stack).

In case you run it from the command line, make sure you use echo -n, otherwise the trailing newline will also be counted.

Output: prints the hamming weight value to the console

The program can be tested here.

\$\endgroup\$
7
  • 1
    \$\begingroup\$ Is Golfscript case-sensitive? If not, you can save a few bits by using BASE instead of base. Update: Just checked, BASE doesn't work. Good solution :) \$\endgroup\$
    – Polynomial
    Commented Jun 7, 2012 at 13:40
  • \$\begingroup\$ @Polynomial I tried that after seeing your TEST/test comment :) But it doesn't work. \$\endgroup\$ Commented Jun 7, 2012 at 13:43
  • \$\begingroup\$ You can get rid of {...}2* by applying 2base~ in the first place. Gets score down to 72. \$\endgroup\$
    – Howard
    Commented Jun 7, 2012 at 14:03
  • \$\begingroup\$ @Howard thanks for this great tip! I've applied it in my answer. \$\endgroup\$ Commented Jun 7, 2012 at 14:14
  • \$\begingroup\$ Your test mechanism is wrong, because you've forgotten an important limitation of your Web GolfScript page. You should have a ; before the string which you substitute for stdin, so that (; is unnecessary. Then Howard's observation gets it down to 65. \$\endgroup\$ Commented Jun 7, 2012 at 14:18
2
\$\begingroup\$

Perl, 80 (22 chars)

Done and done:

perl -0777nE 'say unpack"%32B*"'

Or here's an alternate version with a weight of 77 (21 chars):

perl -0777pE '$_=unpack"%32B*"'

I don't like that version as much, though, because its output omits the final newline.

To calculate the weight, I'm assuming that I'm counting characters in the usual way (excluding the perl -e/-E, but including other option characters). If for some reason people complain about this, then the best I can do without options is 90 (26 chars):

$/=$,,say unpack"%32B*",<>

Sample usage:

$ perl -0777nE 'say unpack"%32b*"' rickroll.txt
7071

Boom.

\$\endgroup\$
2
\$\begingroup\$

Pyth - 15

Disclaimer: This answer isn't eligible to win since Pyth is younger than this challenge.

Uses .B for binary representation and counts the number of "1"'s.

/.BQ\1

Takes input in a string to save on z versus Q.

Try it online here.

\$\endgroup\$
1
\$\begingroup\$

Scala 231

readLine().map(_.toInt.toBinaryString).flatten.map(_.toInt-48)sum

Selftesting code:

"""readLine().map(_.toInt.toBinaryString).flatten.map(_.toInt-48)sum""".map(_.toInt.toBinaryString).flatten.map(_.toInt-48)sum

with selftesting modification.

\$\endgroup\$
2
  • \$\begingroup\$ It's weight 495, not 231. You can't get weight 231 with 126 chars - that's an average of less than 2, and all printable chars (except @ and space, which you don't use) have weight 2 at least. \$\endgroup\$
    – ugoren
    Commented Jun 7, 2012 at 20:27
  • 1
    \$\begingroup\$ @ugoren: But it's only 65 chars. The program is printed nearly twice: Once the code to calculate the hamming weight, and a second time as static input to calculate it for the program. But the calculating part is missing the "readLine()" in front, because it takes the literal input. I tried to clarify the answer itself. \$\endgroup\$ Commented Jun 7, 2012 at 23:15
1
\$\begingroup\$

Java, weight 931 774 499 454

I think this is the only answer at the moment with a weight over about 300.

class H{public static void main(String[]A){System.out.print(new java.math.BigInteger(A[0].getBytes()).bitCount());}}

Expects input as a command line argument.

\$\endgroup\$
1
\$\begingroup\$

GNU sed -r, 467 + 1

(+1 for use of -r - or should that be +4?)

Outputs as a unary value per source line; to convert to a decimal total, redirect output into | tr -d "\n" | wc -c. Counts all printable ASCII characters (32-126), plus linefeed (10).

s@[a-z]@\U& @g
s@[?{}~]@      @g
s@[][/7;=>OW|^]@     @g
s@[-'+.3569:<GKMNSUVYZ\\]@    @g
s@[#%&)*,CEFIJL1248ORTX]@   @g
s@$|[!"$(ABDH0P`]@  @g
y! @!11!

It's hard to avoid listing all characters, but we can reduce this observing that lowercase letters have a Hamming weight of one more than the corresponding uppercase letters. We prefer newline (score 2) over semicolon (score 5) as a statement separator; we prefer @ (score 1) or ! (score 2) over / (score 5) as pattern delimiter.

Note - to get the right sets of characters, I created this table from the one in man ascii, sorted by weight. Just add the scores right and below to get the overall weight of each character:

   2 4   3 5 6   7 
   ---  ------   - 
0:   @   0 P `   p |0

1: ! A   1 Q a   q | 
2: " B   2 R b   r |1
4: $ D   4 T d   t | 
8: ( H   8 X h   x | 

3: # C   3 S c   s | 
5: % E   5 U e   u | 
6: & F   6 V f   v |2
9: ) I   9 Y i   y | 
A: * J   : Z j   z | 
C: , L   < \ l   | | 

7: ´ G   7 W g   w | 
B: + K   ; [ k   { |3
D: - M   = ] m   } | 
E: . N   > ^ n   ~ | 

F: / O   ? _ o     |4
   ---  ------   -  
    1      2     3

This might prove useful to others.

\$\endgroup\$
0
\$\begingroup\$

Julia 262 268

Modified version uses handy 'count_ones' function for a saving of 6 (262)

show(mapreduce(x->count_ones(x),+,map(x->int(x),collect(ARGS[1]))))

Old version using no built in one-counting function (268)

show(mapreduce(x->int(x)-48,+,mapreduce(x->bits(x),*,collect(ARGS[1]))))

Uses command line argument for input.

\$\endgroup\$
0
0
\$\begingroup\$

CJam 52 or 48

If input is not already on the stack (52)

q:i2fbs:s:i:+

If input is on stack (48)

:i2fbs:s:i:+

For example

"Hello World":i2fbs:s:i:+
\$\endgroup\$
0
\$\begingroup\$

Julia, HW 199

H=mapreduce;H(B->B=='1',+,H(P->bits(P),*,collect(A[:])))

With

A="H=mapreduce;H(B->B=='1',+,H(P->bits(P),*,collect(A[:])))"

or by directly inserting the string:

julia> H=mapreduce;H(B->B=='1',+,H(P->bits(P),*,collect("H=mapreduce;H(B->B=='1',+,H(P->bits(P),*,collect(A[:])))")))
199

The ungolfed version (HW 411) looks like this:

bitstring=mapreduce(x->bits(x),*,collect(teststring[:]))
mapreduce(checkbit->checkbit=='1',+,bitstring)

And for the fun of it, here is an optimized version (Hamming Weight 231) of bakerg’s take on the problem:

A=mapreduce;show(A(B->int(B)-48,+,A(B->bits(B),*,collect(H[:]))))

with

H="A=mapreduce;show(A(B->int(B)-48,+,A(B->bits(B),*,collect(H[:]))))"
\$\endgroup\$
0
\$\begingroup\$

HPPPL (HP Prime Programming Language), 74

sum(hamdist(ASC(a),0))

The HP Prime graphing calculator has a built-in hamdist() function. The hamming weight of each character is the same as the hamming distance from 0.

ASC(string) creates an array of the ASCII values of each character in a string.

hamdist(value,0) computes the hamming distance from 0 for each ASCII value

sum() sums up all values.

Calculating the hamming weight of its own source code:

Hamming Weight HPPPL

\$\endgroup\$
0
\$\begingroup\$

05AB1E, weight 17 (4 bytes)

ÇbSO

Try it online or verify some more test cases.

Explanation:

Ç       # Convert the characters in the (implicit) input to their ASCII decimal values
        #  i.e. "Test" → [84,101,115,116]
 b      # Convert those values to binary
        #  i.e. [84,101,115,116] → ["1010100","1100101","1110011","1110100"]
  S     # Split it into a list of 0s and 1s (implicitly flattens)
        #  i.e. ["1010100","1100101","1110011","1110100"]
        #   → [1,0,1,0,1,0,0,1,1,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0]
   O    # Sum those (and output implicitly)
        #  i.e. [1,0,1,0,1,0,0,1,1,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0] → 16
\$\endgroup\$
0
\$\begingroup\$

Perl 6, 102

+*.ords>>.base(2).comb(~1)

Try it online!

While this isn't code golf, the shortest solution also seems to have the smallest hamming weight...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.