Calculate hamming weight with low hamming weight

19

4

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

Polynomial

Posted 2012-06-07T13:02:29.230

Reputation: 4 082

if we take 0x20/ASCII 32 as the reference, isn't the humming weight of hello world 10 rather than 11? – Cristian Lupascu – 2012-06-07T13:11:32.747

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 – 2012-06-07T13:12:58.943

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 – 2012-06-07T13:16:31.960

@ugoren A solution with lower-value ASCII characters has a lower hamming weight. – Polynomial – 2012-06-07T13:18:23.190

1Now it all makes sense. USE UPPERCASE, BEWARE OF ~ AND o. – ugoren – 2012-06-07T13:22:33.533

@ugoren Yup, pretty much. TEST has a weight of 13, whereas test has a weight of 17. – Polynomial – 2012-06-07T13:25:27.253

So Hamming weight of a string is the sum of the Hamming weights of the characters, or is it the number of unique bits set? – user unknown – 2012-06-07T13:51:17.353

@userunknown Sum of the Hamming weights of the characters. – Polynomial – 2012-06-07T13:59:03.420

@Polynomial Now that you've corrected the measurement of the Hamming weight, will you be lifting the ban on Whitespace? – breadbox – 2012-06-07T19:08:29.843

@breadbox Good idea, though I can't imagine solutions would be particularly competitive ;) – Polynomial – 2012-06-07T19:11:57.543

Tip: Name your variables A, B, D, H, or P. – dan04 – 2012-06-08T03:39:32.237

Answers

6

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

ɐɔıʇǝɥʇuʎs

Posted 2012-06-07T13:02:29.230

Reputation: 4 449

8

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

Gareth

Posted 2012-06-07T13:02:29.230

Reputation: 11 678

Not trying to be a buzzkill, but the rules ask for a program, not a fragment. – FUZxxl – 2015-06-23T10:39:51.113

There's only one way to write this :) – ephemient – 2012-06-07T14:22:32.547

There isn't... I found a solution that has a hamming weight of one lower. – ɐɔıʇǝɥʇuʎs – 2014-06-23T06:33:40.400

5

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

ephemient

Posted 2012-06-07T13:02:29.230

Reputation: 1 601

Great minds think alike. :-) – Gareth – 2012-06-07T14:20:53.220

5

Python, 189

print sum(bin(ord(A)).count("1")for A in raw_input())

Keith Randall

Posted 2012-06-07T13:02:29.230

Reputation: 19 865

2The Python 3 equivalent, print(sum(bin(ord(A)).count('1')for A in input())), has a score of 180. – dan04 – 2012-06-08T03:42:31.933

4@dan04: Use double quotes instead of single for 176. – Keith Randall – 2012-06-08T03:56:48.187

5

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.

ceased to turn counterclockwis

Posted 2012-06-07T13:02:29.230

Reputation: 5 200

1+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 – 2012-06-07T20:09:26.943

5

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

walpen

Posted 2012-06-07T13:02:29.230

Reputation: 3 237

1I'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 – 2012-06-08T10:08:02.727

1A 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 – 2012-06-08T12:02:33.673

I'm still not convinced it's the former category, rather than the latter. – Polynomial – 2012-06-08T12:12:03.320

1

Well here's a unary to C compiler that works fine with null characters: http://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.

– walpen – 2012-06-08T12:30:54.820

3If you can't actually run it, it's not really a solution. – Polynomial – 2012-06-08T12:33:09.913

4

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 – 2012-06-08T23:13:08.613

4

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.

Cristian Lupascu

Posted 2012-06-07T13:02:29.230

Reputation: 8 369

1Is 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 – 2012-06-07T13:40:21.087

@Polynomial I tried that after seeing your TEST/test comment :) But it doesn't work. – Cristian Lupascu – 2012-06-07T13:43:12.330

You can get rid of {...}2* by applying 2base~ in the first place. Gets score down to 72. – Howard – 2012-06-07T14:03:05.257

@Howard thanks for this great tip! I've applied it in my answer. – Cristian Lupascu – 2012-06-07T14:14:17.910

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 – 2012-06-07T14:18:42.263

And then down to 58 using % instead of /]. – Howard – 2012-06-07T14:24:52.817

@PeterTaylor thanks for pointing that out; I also ran it from the commandline and it works fine – Cristian Lupascu – 2012-06-07T14:58:38.743

4

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

ugoren

Posted 2012-06-07T13:02:29.230

Reputation: 16 527

Hah, I utterly failed to understand your first sentence until just now. – breadbox – 2012-06-08T03:35:00.580

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 – 2012-06-09T00:29:50.613

@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 – 2012-06-10T06:19:19.577

@ugoren: Depends on the convention/definition of unary. E.g. http://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 – 2012-06-10T09:54:18.100

@schnaader, OK, but I think it's stretching the requirement "as a number" too far. – ugoren – 2012-06-10T10:11:56.760

2

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.

Maltysen

Posted 2012-06-07T13:02:29.230

Reputation: 25 023

2

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.

breadbox

Posted 2012-06-07T13:02:29.230

Reputation: 6 893

1

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.

SuperJedi224

Posted 2012-06-07T13:02:29.230

Reputation: 11 342

1

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.

Toby Speight

Posted 2012-06-07T13:02:29.230

Reputation: 5 058

1

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.

user unknown

Posted 2012-06-07T13:02:29.230

Reputation: 4 210

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. – ugoren – 2012-06-07T20:27:52.543

1@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. – user unknown – 2012-06-07T23:15:37.143

0

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

Kevin Cruijssen

Posted 2012-06-07T13:02:29.230

Reputation: 67 575

0

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

Jo King

Posted 2012-06-07T13:02:29.230

Reputation: 38 234

0

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.

bakerg

Posted 2012-06-07T13:02:29.230

Reputation: 81

0

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:+

bakerg

Posted 2012-06-07T13:02:29.230

Reputation: 81

0

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[:]))))"

M L

Posted 2012-06-07T13:02:29.230

Reputation: 2 865

0

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

M L

Posted 2012-06-07T13:02:29.230

Reputation: 2 865