Calculate hamming weight with low hamming weight

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
-
 if we take 0x20/ASCII 32 as the reference, isn't the humming weight of hello world 10 rather than 11? – w0lf Jun 7 '12 at 13:11 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. – ugoren Jun 7 '12 at 13:12 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. – Polynomial Jun 7 '12 at 13:16 @ugoren A solution with lower-value ASCII characters has a lower hamming weight. – Polynomial Jun 7 '12 at 13:18 Now it all makes sense. USE UPPERCASE, BEWARE OF ~ AND o. – ugoren Jun 7 '12 at 13:22

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
-
 There's only one way to write this :) – ephemient Jun 7 '12 at 14:22

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
-
 Great minds think alike. :-) – Gareth Jun 7 '12 at 14:20

Golfscript 8472 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.

-
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 :) – Polynomial Jun 7 '12 at 13:40
@Polynomial I tried that after seeing your TEST/test comment :) But it doesn't work. – w0lf Jun 7 '12 at 13:43
You can get rid of {...}2* by applying 2base~ in the first place. Gets score down to 72. – Howard Jun 7 '12 at 14:03
@Howard thanks for this great tip! I've applied it in my answer. – w0lf Jun 7 '12 at 14:14
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. – Peter Taylor Jun 7 '12 at 14:18

QBasic, 322311286 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.

-
+1 for using one of my favourite languages of all time. It's the first language I learnt to code in on a PC. – Polynomial Jun 7 '12 at 20:09

C, weight 322263 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].

-
 Hah, I utterly failed to understand your first sentence until just now. – breadbox Jun 8 '12 at 3:35 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("@");} – schnaader Jun 9 '12 at 0:29 @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. – ugoren Jun 10 '12 at 6:19 @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". – schnaader Jun 10 '12 at 9:54 @schnaader, OK, but I think it's stretching the requirement "as a number" too far. – ugoren Jun 10 '12 at 10:11

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.

-

Python, 189

print sum(bin(ord(A)).count("1")for A in raw_input())
-
The Python 3 equivalent, print(sum(bin(ord(A)).count('1')for A in input())), has a score of 180. – dan04 Jun 8 '12 at 3:42
@dan04: Use double quotes instead of single for 176. – Keith Randall Jun 8 '12 at 3:56

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).

-
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. – Polynomial Jun 8 '12 at 10:08
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). – walpen Jun 8 '12 at 12:02
I'm still not convinced it's the former category, rather than the latter. – Polynomial Jun 8 '12 at 12:12
If you can't actually run it, it's not really a solution. – Polynomial Jun 8 '12 at 12:33
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) – walpen Jun 8 '12 at 23:13
show 1 more comment