# Generate 3 random numbers such that the sum is below a number, or within a range

I'm writing a program for fun which generates random colours for text. (If you're curious: https://github.com/Arunscape/acat)

So, I have 3 variables $$r, g$$, and $$b$$ , each of which can be any integer $$\in [0, 256)$$

I figure that if I want dark text on a light background, or light text on a dark background, I should generate $$r,g,b$$ such that their sum is within a range, either

$$r + g + b \leq 255 \quad r,g,b \in [0, 255]$$ for dark text

or

$$r + g + b \geq 255 \quad r,g,b \in [0, 255]$$ for light text

Here is my thought process so far for approaches I could take:

1. generate $$r$$, let's say we get $$r=100$$
2. g = random_num_in_range($$0, 256-r)$$, let's say we get $$g=100$$
3. b = random_num_in_range(0, 256-r-g), let's say we get $$b=50$$

In this example, I would get a dark-ish yellow colour for use with a light background However, because r is always the first number to be generated, would this algorithm have some sort of bias, or would the generated colours be random?

If this algorithm does work, can I make it more efficient? I will be generating lots of colours, so the less CPU cycles I can waste, the better.

Another approach I'm thinking I could take is, instead of generating 3 random numbers for each colour, is it possible to say, generate a number between 0 and $$256^3 - 1$$ and then map the number to r,g,b values. (or rather I would generate numbers in the range, $$[0,0x7FFFFF]$$ for dark values and $$[0x800000, 0xFFFFFF]$$ for lighter values.

Now that I think of it, that's kind of close to hex colour codes, except that for hex colour codes, the 2 leftmost digits are r, the 2 middle are g, and the 2 left ones are for b

Or, is there some other approach that I completely missed that's much better than what I came up with? 😄

• Just randomize also the order of variables when choosing the random numbers to get rid of the bias. – trancelocation Jul 16 '20 at 3:07

Your approach will definitely bias $$r$$ high-it will average $$127.5$$ and $$b$$ low. A simple approach is to generate four numbers, $$r,g,b$$ in a fixed range and a sum to normalize to. Multiply each one by $$\frac {desired sum}{actual sum}$$ and you are there. Certainly you can generate one random number and split it into four bytes, however the low order bits of a random number are often much less random than the high order bits.
I would be surprised if a simple sum of $$r+g+b$$ got you a good split of light vs. dark colors. Note that $$255$$ is $$\frac 13$$ of the way up, not $$\frac 12$$.