How to find the unique sums in the values 1,2,4,8,16, 32

3.1k Views Asked by At

I apologize but I'm not sure what you would even call this problem. I have some data that provide a numeric code for race as follows:

hispanic(1) + american_indian_or_alaska_native(2) + asian(4) + black_or_african_american(8) + native_hawaiian_or_other_pacific_islander(16) + white(32)

So for example, a 5 represents a person who identifies as Asian and Hispanic (4 + 1), and a 25 represents a person who identifies as Pacific Islander, Black, and Hispanic (16 + 8 + 1).

I am trying to write a program that will retrieve what races are present from the given number. I figure there must be an equation that can determine the combination without detailing every unique combination, but I might be wrong! I tried to think about using modulo but I didn't get very far.

Thanks, and if you have suggestions for tags, please comment as I'm not sure where this fits into mathematics.

*edit Thanks everyone! This really helped me to think about the problem and generate an efficient solution. Answering my question didn't depend on using SAS but here is the SAS code I ended up using, which I think shows intuitively how to solve the problem:

data want; 
    set have; 

/* convert decimal to 6-place binary */
    eth_bin = put(ethnicity, binary6.);  

/* if 1st digit is 1 then race is present, and so on*/ 
    if substr(eth_bin, 1, 1) = 1 then white = "Yes"; 
    if substr(eth_bin, 2, 1) = 1 then pacific_islander = "Yes"; 
    if substr(eth_bin, 3, 1) = 1 then black = "Yes"; 
    if substr(eth_bin, 4, 1) = 1 then asian = "Yes"; 
    if substr(eth_bin, 5, 1) = 1 then american_indian = "Yes"; 
    if substr(eth_bin, 6, 1) = 1 then hispanic = "Yes"; 
run; 
7

There are 7 best solutions below

1
On BEST ANSWER

Based on your example, I think the right SAS syntax to do it by bit manipulation would be something like

if BAND(ethnicity, 32) ^= 0 then white = "Yes"; 
if BAND(ethnicity, 16) ^= 0 then pacific_islander = "Yes"; 
if BAND(ethnicity, 8) ^= 0 then black = "Yes"; 
if BAND(ethnicity, 4) ^= 0 then asian = "Yes"; 
if BAND(ethnicity, 2) ^= 0 then american_indian = "Yes"; 
if BAND(ethnicity, 1) ^= 0 then hispanic = "Yes"; 

Note that this works because

 1 = blshift(1,0)
 2 = blshift(1,1)
 4 = blshift(1,2)
 8 = blshift(1,3)
16 = blshift(1,4)
32 = blshfit(1,5)

which could come handy if you need to do more complex processing where a loop would be nicer than repeating the same code six times.

3
On

Notice that the numbers $1, 2, 4, 8, 16, 32$ are all perfect powers of $2$. This means that from any sum of them, the individual components can always be retrieved because there is a unique way to express a number as a binary number. One way to retrieve the racial info is keep dividing by $2$ and getting the remainder. Every remainder of $1$ indicates a certain race (depending on the stage of division). If the remainder is $0$, that race is not present. To elaborate, roughly you follow this algorithm:

  1. Let $n$ be your number with the racial info.
  2. While $n$ is non-zero, re-assign $n$ to $\lfloor \frac{n}{2} \rfloor$ and make a note of the remainder. If the remainder is $1$, then that race is present, where the race starts at Hispanic and so on.
  3. When $n=0$ you are finished, there are no more races.

Update: Henning Makholm's suggestions to use bitwise operators is in fact a more elegant solution, programmatically, but may be harder to grasp intuitively.

0
On

What you do is look at your numbers in binary. For example, $$ 5_{10} = 101_{2}, $$ so hispanic and asian would be true, all others -- false.

0
On

$$0\leq N\leq63$$ $$N=\sum_{k=0}^{5}a_k\cdot 2^k$$ $$a_5 = \left[\frac{N}{2^5}\right]$$ $$a_4 = \left[\frac{\mod (N,2^5)}{2^4}\right]$$ $$...$$ $$a_k = \left[\frac{\mod (N,2^{k+1})}{2^k}\right]$$ $$...$$ $$a_0 = \left[\frac{\mod (N,2)}{1}\right]$$

This can be done concurrently for all $k$. (No need to wait for remainder from the previous stage.)

2
On

Open MS Excel. Type $DEC2BIN(5)$, for example, if $5$ is the number of the person. Each $1$ or $0$ tells you whether the person belongs to the race or not.

0
On

hispanic(1)
american_indian_or_alaska_native(2)
asian(4)
black_or_african_american(8) native_hawaiian_or_other_pacific_islander(16)
white(32)
An example (not an entire program, just a routine) for QB64:
[
IF (yourcode%% = 0) THEN
-->PRINT "no preference"
ELSE
-->FOR i%% = 0 TO 5
----->j%% = 2 ^ i%%
----->IF (j%% AND yourcode%%) THEN
-------->SELECT CASE j%%
----------->CASE 1: v\$ = "hisp"
----------->CASE 2: v\$ = "amer"
----------->CASE 4: v\$ = "asian"
----------->CASE 8: v\$ = "black"
----------->CASE 16: v\$ = "pacific"
----------->CASE 32: v\$ = "white"
-------->END SELECT
-------->PRINT v\$
----->END IF
-->NEXT 'i%%
END IF
]
You can abbreviate your categories or spell them out in full. All pertinent categories will be listed for a given code.

0
On

I don't know about SAS, but most programming languages have a bitwise AND operator. This is usually the word AND or the symbol & (the symbol && behaves slightly differently as it compares only TRUE and FALSE.) Thus there is no need to actually convert into a human readable binary.

Thus for a person identifying as american indian / white 100010 (34 decimal) assigned we get

a=34

Hispanic          a&1=0
American Indian   a&2=2
Asian             a&4=0
Black             a&8=0
Pacific Island    a&16=0
White             a&32=32

In many languages (C, Python, etc) a nonzero value will be interpreted as TRUE (truthy) and a zero value will be interpreted as FALSE (falsy).

In other languages, the behaviour may be different. For example in Ruby all values (including zero) are considered truthy, with the only exceptions being NIL (absence of data) and the FALSE itself. So we get slightly different code:

C:

if(a&4)puts("Asian");

Ruby:

puts "Asian" if a&4>0