7
\$\begingroup\$

For example, in traditional web hexadecimal, a certain base-16 number represents an RGB value. For example, 45A19C equals (69,161,156) in RGB.

You'll be converting from that number to RGB value, however, instead you'll be given that number in base-10 rather than base 16.

So in the example used above, 45A19C would equal 4563356 in base-10. Thus 4563356 converted to RGB would equal (69,161,156).

So assume the integer given is previously stored in variable n and is between 0 and 16777215. Take number n and convert it to RGB values between 0 and 255. Return or save in a variable the three values as a list [r,g,b].

An RGB to RGB int can be found here. This link converts the opposite of what your trying to do.

Shortest code wins.

If clarification is needed, please ask so I can fix my question to be more helpful.

\$\endgroup\$
7
  • \$\begingroup\$ Full program, function, or code snippet? \$\endgroup\$ Jan 4, 2015 at 0:34
  • 3
    \$\begingroup\$ @TheBestOne The question explicitly says we can assume the input to be stored in a variable n, so I think that implies snippet. \$\endgroup\$ Jan 4, 2015 at 2:07
  • 1
    \$\begingroup\$ The question asks for the three values "as a list" - most of the answers posted I would say return the values as an array, not a list. If an array is permitted then the winning answer has no length at all in most assembly languages. \$\endgroup\$ Jan 4, 2015 at 18:08
  • 1
    \$\begingroup\$ @SideshowBob Presumably only if you 'run' it on a big-endian machine? \$\endgroup\$
    – Uri Granta
    Jan 4, 2015 at 21:33
  • 2
    \$\begingroup\$ I'm really concerned about inclarity in the I/O rules here. Given that in many languages, a 24-bit variable would naturally be stored as a list of three bytes, how can we distinguish what counts as input and output? \$\endgroup\$
    – user62131
    Jun 11, 2017 at 3:43

18 Answers 18

16
\$\begingroup\$

AVR ABI, 0

Quantities larger than the registers in the AVR's registers are represented with multiple registers. So, when passing in a 32-bit 'n' to a function, it is passed as 4x8-bit registers. Effectively R(r24),G(r23), and B(r22) are directly addressable without any additional work by virtue of the CPU's register addressing.

Here's some 'C' code for the unpacking operation:

unsigned char r( unsigned long n ){return n>>16&255;}
unsigned char g( unsigned long n ){return n>>8&255;}
unsigned char b( unsigned long n ){return n>>0&255;}

disassembled examples from avr-gcc 4.8:

.global r
.type   r, @function
r:
ret
.size   r, .-r

.global g
.type   g, @function
g:
mov r24,r23
ret
.size   g, .-g

.global b
.type   b, @function
b:
mov r24,r22
ret
.size   b, .-b

For red, GCC just emits the return code since the red byte just happens to be in the return register already. For green and blue it copies the corresponding register into the return register and returns. The actual packing/unpacking is handled by the ABI - when done somewhere other than a function call boundary, it's handled purely by the register addressing. Both the copies and return opcode are overhead required to view this happening in the CPU - the compiler can use these registers directly if not required to place the result in the return register. Free RGB packing/unpacking is available when handing any 32-bit integer.

Another way to think about it is that the AVR's registers represent large numbers as a list of 8-bit registers, and that list happens to unpack RGB for us.

\$\endgroup\$
14
\$\begingroup\$

Java 35 31 bytes.

Yay!!! A java answer under 40 bytes.

new int[]{n>>16,n>>8&255,n&255}

Interestingly, java integers are always stored as Binary numbers.

Consequently this snippet returns [69,161,156] whether n = 0x45A19C, 4563356, or 0b10001011010000110011100.

\$\endgroup\$
4
  • 6
    \$\begingroup\$ Well, any language that doesn't intentionally use some nonstandard representation will store integers in binary -- after all, that's what every modern processor (that I know of) uses. \$\endgroup\$
    – rationalis
    Jan 4, 2015 at 5:08
  • \$\begingroup\$ As the max value is 16777215, you don't need the first binary and \$\endgroup\$
    – edc65
    Jan 4, 2015 at 9:27
  • \$\begingroup\$ @edc65 it still assures correct sign \$\endgroup\$ Jan 4, 2015 at 11:33
  • \$\begingroup\$ " n and is between 0 and 16777215" what sign? \$\endgroup\$
    – edc65
    Jan 4, 2015 at 12:42
7
\$\begingroup\$

CJam, 11 bytes

NG6#+256b1>

This assumes that the base-10 integer is stored in N (there are no lower-case variable names), and it leaves the required list on the stack. This simply gets the digits in base 256. To take care of leading zeroes, we first add 2563 = 166. This will always give us 4 digits, the first one being 1, so at the end we slice off that extraneous digit with 1>:

N           "Push N.";
 G6#        "16^6.";
    +       "Add.";
     256b   "Get base-256 digits.";
         1> "Slice off leading digit.";

Test it here. You can use the following framework to initialise N and view the stack afterwards:

4563356:N;
NG6#+256b1>
ed

Of course, if I'm allowed to just have the input on the stack, instead of storing it in N, the solution is only 10 bytes, G6#+256b1>.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Should the list contain fewer than three values for N<65536? \$\endgroup\$
    – ngn
    Jan 4, 2015 at 9:17
  • 2
    \$\begingroup\$ Tested, fail with number smaller than 65536 \$\endgroup\$
    – edc65
    Jan 4, 2015 at 9:30
  • \$\begingroup\$ @ngn Good catch, fixed. \$\endgroup\$ Jan 4, 2015 at 10:09
6
\$\begingroup\$

Ostrich 0.5.0, 13 bytes

n16 6?+256B1>

Might as well post this just to promote Ostrich, even though it's essentially the same as @MartinBüttner's. (The only thing I changed was b -> B, since all built-in functions are either symbols or capital letters in Ostrich, and G -> 16 since Ostrich doesn't have that fancy built-in number (which it really should).)

Idential translation to Golfscript (18 bytes):

n 16 6?+256base 1>
\$\endgroup\$
3
  • 2
    \$\begingroup\$ So how does ostrich differ from cjam? Something must make it special but the contents of the doc directory don't really help. \$\endgroup\$ Jan 4, 2015 at 9:22
  • 1
    \$\begingroup\$ This fails on numbers less than 65536 \$\endgroup\$
    – Optimizer
    Jan 4, 2015 at 10:09
  • \$\begingroup\$ @Optimizer Good catch; fixed. \$\endgroup\$
    – Doorknob
    Jan 4, 2015 at 16:17
3
\$\begingroup\$

Mathematica, 22 bytes

IntegerDigits[n,256,3]

Basically the same as my CJam answer. But I don't know a lot of languages that handle base conversion with arbitrary bases, so I thought I'd post both versions.

This one handles leading zeroes by using IntegerDigits' third parameter which pads the result to specified number of digits.

\$\endgroup\$
3
\$\begingroup\$

APL, 8 characters

n⊤⍨3⍴256

3⍴256  is 256 256 256
B⊤⍨A   is A⊤B
A⊤B    encodes B in a number system specified by A
         It doesn't have to use a uniform radix, e.g.:
         365 24 60 60 1000 ⊤ time
\$\endgroup\$
1
\$\begingroup\$

Ruby, 25

[16,8,0].map{|x|n>>x&255}

The javascript answer by @Oriol is valid ruby as well, but at least this uses ruby features... (and it's a byte shorter).

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

Rebol - 43 40

x: to-tuple to-hex n reduce[x/6 x/7 x/8]

Example:

>> n: 4563356
== 4563356

>> x: to-tuple to-hex n reduce [x/6 x/7 x/8]
== [69 161 156]


Alternative 40 char solution:

map-each x[-16 -8 0][(shift n x)and 255]
\$\endgroup\$
1
\$\begingroup\$

J (10)

(3#256)#:]

Demonstration:

    f=:(3#256)#:]
    f 4563356
69 161 156
    f 12
0 0 12
\$\endgroup\$
1
\$\begingroup\$

C/C++, 31

int r=n>>16,g=n>>8&255,b=n&255;

Convergently evolved to TheBestOne's answer, with the same size.

C/C++, 31

int c[]={n>>16,n>>8&255,n&255};

This one actually makes a list(array). I'm not sure if it would count without "int c[]=". If so, it would be 23 bytes

Also added Uri Zarfaty's optimization to not mask the red channel, as by this point blue and green are already shifted away.

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

Erlang, 25 Bytes

binary_to_list(<<N:24>>).

Using the bit syntax, extracts 24 bits from N, which results in a binary of size 3.

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

JavaScript, 26 22

[n>>16,n>>8&255,n&255]

Inspired by TheBestOne's answer. I don't know bitwise operators very much, but it seems to work.

\$\endgroup\$
1
  • \$\begingroup\$ As the max value is 16777215, you don't need the first binary and [n>>16,n>>8&255,n&255] \$\endgroup\$
    – edc65
    Jan 4, 2015 at 9:27
0
\$\begingroup\$

Python 3, 23 bytes

*c,=n.to_bytes(3,'big')

If bare expressions are allowed then the following is one byte shorter:

[n>>16,n>>8&255,n&255]
\$\endgroup\$
0
\$\begingroup\$

Ruby, 44

Not a winner, but this makes use of Ruby's (very useful) optional parameters to String#to_i and Integer#to_s. They both take a base.

f=->i{i.to_s(16).scan(/../){|x|p x.to_i 16}}
\$\endgroup\$
0
\$\begingroup\$

Python, 28 bytes

The final value is stored in c

c=[n>>16&255,n>>8&255,n&255]
\$\endgroup\$
0
\$\begingroup\$

C - 56 characters, but no calculations required

C doesn't really have lists, but would just like to point out that if you know the architecture (and there are macros to do this for you) you can retrieve RGB with no calculation, just defining types.

Something like this:

enum {B, G, R};
typedef union {int i; unsigned char u[3];}T;

Then you access like this:

#include <stdio.h>

int main(void)
{
    T t;

    // Set the color
    t.i = 0x45A19C;

    // Pull out the primaries
    printf("%u %u %u\n", t.u[R], t.u[G], t.u[B]);

    return 0;
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ There are some portability problems with this approach: int can be as small as 16 bits, endianness would require reordering the enum and possibly adding a dummy before the first color. \$\endgroup\$
    – rsaxvc
    Jan 14, 2015 at 4:13
  • \$\begingroup\$ It's hardly "free", except in AVR or other 8-bit machines. If your value is in memory, it takes three loads to get the bytes into 3 separate registers. Or if it's in a register, the compiler will emit shift/mask instructions when you type-pun it. \$\endgroup\$ Jul 20, 2017 at 18:25
  • 1
    \$\begingroup\$ This would be a better answer if you gave a specific platform it worked on. For example, big-endian MIPS32. See also en.wikipedia.org/wiki/RGBA_color_space#Representation \$\endgroup\$ Jul 20, 2017 at 18:27
0
\$\begingroup\$

dc, 10

dc is a stack-based language so I'm assuming input and output on the stack is OK:

256~r256~r
\$\endgroup\$
0
\$\begingroup\$

ARM Assembly, 45

UXTB r1, r0, 16
UXTB r2, r0, 8
UXTB r3, r0, 0

Assuming N is passed in to R0, R1 contains Red, R2 contains Blue, and R3 contains Green. The result list is stored in r1,r2,r3.

Assembles to 12B of ARM instructions or 6B of 16-bit Thumb instructions.

\$\endgroup\$
0

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.