<p>There's actually a reasonably good mathematical reason for doing bit replication:</p>

<p>First note that the n-bit string, <span class="math-container">$N$</span>, actually represents the value <span class="math-container">$\frac{N}{2^n-1}$</span> and we want to produce the m-bit string, <span class="math-container">$M$</span>, where <span class="math-container">$n&lt;m$</span> and
<span class="math-container">$$\frac{N}{2^n-1}\approx\frac{M}{2^m-1}$$</span></p>

<p>We first scale numerator and denominator with
<span class="math-container">$$\frac{N.(2^n+1)}{(2^n-1)(2^n+1)}\approx \frac{M}{2^m-1}$$</span>
and this simplifies to 
<span class="math-container">$$\frac{N.(2^n+1)}{2^{2n}-1}\approx \frac{M}{2^m-1}$$</span></p>

<p>In your case, <span class="math-container">$n\in \{5,6\}$</span> and <span class="math-container">$m=8$</span> and we can "stop" here, but but the process can be repeated, (ad nauseum), if m >> n.</p>

<p>We next make the approximation...
<span class="math-container">$$\frac{N.(2^n+1)}{2^{2n}}\approx \frac{M}{2^m}$$</span> which simplifies to 
<span class="math-container">$$\frac{N.(2^n+1)}{2^{2n-m}}\approx M $$</span></p>

<p>Note that <span class="math-container">$N.(2^n+1)$</span> is equivalent to repeating the n-bit string, to create a 2n-bit string, and the division shifts off the <span class="math-container">$2n-m$</span> LSBs to leave an M bit result. </p>

<p>QED</p>

<p>Of course, the  'correct' calculation is <span class="math-container">$M=\lfloor(\frac{(2^m-1) N}{2^n-1}+\frac{1}{2}\rfloor$</span> but this approximation, in general, works <em>most</em> of the time. Of course there are times when it's inaccurate, but IIRC only by one bit and relatively infrequently.</p>

CC BY-SA 4.0
2018-10-25T02:12:40.047Z
Thank you for a detailed explanation with nice formulas. I was curious about the error introduced by the approximation so I made this graph that compares both formulas: https://www.desmos.com/calculator/cvaqofyvbf . However I prefer PaulHK's answer since it is easier to understand.
wip
CC BY-SA 4.0
2018-10-25T11:54:32.073Z
Minor quibble, if m >= 2n then you need to change your "approximation" equation.  An extreme, example, is if n=1, then you need to repeat the string 8 times (i.e. perform log2(8)=3 steps).

Of course, if you *pad* with "10...0" instead of all zeros, then on average you'll have a lower error, but lose the extremes.

"However I prefer PaulHK's answer" :-)  Well, there's no accounting for taste 8P.
Simon F
CC BY-SA 4.0
2018-10-23T13:27:41.900Z
2018-10-24T08:16:38.870Z
2018-10-24T08:16:38.870Z
Simon F
<p>Without replicating the bits the LSBs will be 0, so for the maximum value of 0x1f (max for 5 bits) it would expand to 0xf8 when converted to 8 bit. What you want is 0xff so the range of 0x00->0x1f will be mapped to 0x00->0xff instead of 0x00->0xf8. Without merging the LSB you would not be able to convert 0x1f,0x1f,0x1f to white (0xff,0xff,0xff). Incidentally this is the same as N*0xff/0x1f.</p>

<pre><code>Example: 

left shift only (&lt;&lt; 3)
%---00001 -&gt; %00001000     (0x01 -&gt; 0x08)
%---10000 -&gt; %10000000     (0x10 -&gt; 0x80)
%---11111 -&gt; %11111000     (0x1f -&gt; 0xf8)

merging MSB to LSB 
%---00001 -&gt; %00001000     (0x01 -&gt; 0x08)
%---10000 -&gt; %10000100     (0x10 -&gt; 0x84)
$---11111 -&gt; %11111111     (0x1f -&gt; 0xff)
</code></pre>

CC BY-SA 4.0
2022-10-15T09:37:32.260Z
_"Incidentally this is the same as N*0xff/0x1f"_ Note it differs for values `{3,7,24,28}` which yield `{24,57,198,231}` with bit replication but `{25,58,197,230}` for `round(N*255/31)`. All other values are the same (using floor or ceil instead of causes more error). So, it's a quite close approximation. However `floor(N*33/4)` does exactly match for all N with bit replication.
Dwayne Robinson
CC BY-SA 4.0
2018-10-25T02:03:36.403Z
2018-10-25T09:33:36.313Z
2018-10-25T09:33:36.313Z
PaulHK
<p>I have seen in some computer graphics software's code bases that sometimes the higher bits of RGB565-format image data are replicated into the lower bits when converting to higher-bit-depth format RGBA8888.  </p>

<p>I have found for example the comment by user "eq" in <a href="https://www.gamedev.net/forums/topic/385638-rgb8888-to-rgb565-pixel-format-conversion/" rel="noreferrer">this gamedev.net thread</a>:</p>

<blockquote>
  <p>I prefer to replicate the higher bits into the undefined lower bits:<br>
  R8 = (R5 &lt;&lt; 3) | (R5 >> 2);</p>
</blockquote>

<p>However I do not understand the reason behind.  </p>

<p>What use the purpose of replicating those bits into the converted data?</p>

<color-management><conversion>
Why replicating the higher bits of RGB565 when converting to RGBA8888?
wip
# Why replicating the higher bits of RGB565 when converting to RGBA8888?

(Asked by: username_0 on 2018-10-23)

I have seen in some computer graphics software's code bases that sometimes the higher bits of RGB565-format image data are replicated into the lower bits when converting to higher-bit-depth format RGBA8888.

I have found for example the comment by user "eq" in [this gamedev.net thread](https://www.gamedev.net/forums/topic/385638-rgb8888-to-rgb565-pixel-format-conversion/):

> I prefer to replicate the higher bits into the undefined lower bits:  
> R8 = (R5 << 3) | (R5 >> 2);

However I do not understand the reason behind.

What use the purpose of replicating those bits into the converted data?

**Tags:** color-management, conversion


---

## 2 answers

### Answer by username_2 on 2018-10-25. Score: 7 | Accepted answer

Without replicating the bits the LSBs will be 0, so for the maximum value of 0x1f (max for 5 bits) it would expand to 0xf8 when converted to 8 bit. What you want is 0xff so the range of 0x00->0x1f will be mapped to 0x00->0xff instead of 0x00->0xf8. Without merging the LSB you would not be able to convert 0x1f,0x1f,0x1f to white (0xff,0xff,0xff). Incidentally this is the same as N\*0xff/0x1f.

```
Example: 

left shift only (<< 3)
%---00001 -> %00001000     (0x01 -> 0x08)
%---10000 -> %10000000     (0x10 -> 0x80)
%---11111 -> %11111000     (0x1f -> 0xf8)

merging MSB to LSB 
%---00001 -> %00001000     (0x01 -> 0x08)
%---10000 -> %10000100     (0x10 -> 0x84)
$---11111 -> %11111111     (0x1f -> 0xff)

```

> **Comments:**
> **username_3**: _"Incidentally this is the same as N*0xff/0x1f"_ Note it differs for values `{3,7,24,28}` which yield `{24,57,198,231}` with bit replication but `{25,58,197,230}` for `round(N*255/31)`. All other values are the same (using floor or ceil instead of causes more error). So, it's a quite close approximation. However `floor(N*33/4)` does exactly match for all N with bit replication.  

---

### Answer by username_1 on 2018-10-23. Score: 7

There's actually a reasonably good mathematical reason for doing bit replication:

First note that the n-bit string, $N$, actually represents the value $\frac{N}{2^n-1}$ and we want to produce the m-bit string, $M$, where $n<m$ and
$$\frac{N}{2^n-1}\approx\frac{M}{2^m-1}$$

We first scale numerator and denominator with
$$\frac{N.(2^n+1)}{(2^n-1)(2^n+1)}\approx \frac{M}{2^m-1}$$
and this simplifies to
$$\frac{N.(2^n+1)}{2^{2n}-1}\approx \frac{M}{2^m-1}$$

In your case, $n\in \{5,6\}$ and $m=8$ and we can "stop" here, but but the process can be repeated, (ad nauseum), if m >> n.

We next make the approximation...
$$\frac{N.(2^n+1)}{2^{2n}}\approx \frac{M}{2^m}$$ which simplifies to
$$\frac{N.(2^n+1)}{2^{2n-m}}\approx M $$

Note that $N.(2^n+1)$ is equivalent to repeating the n-bit string, to create a 2n-bit string, and the division shifts off the $2n-m$ LSBs to leave an M bit result.

QED

Of course, the 'correct' calculation is $M=\lfloor(\frac{(2^m-1) N}{2^n-1}+\frac{1}{2}\rfloor$ but this approximation, in general, works *most* of the time. Of course there are times when it's inaccurate, but IIRC only by one bit and relatively infrequently.

> **Comments:**
> **username_0**: Thank you for a detailed explanation with nice formulas. I was curious about the error introduced by the approximation so I made this graph that compares both formulas: https://www.desmos.com/calculator/cvaqofyvbf . However I prefer username_2's answer since it is easier to understand.  
> **username_1**: Minor quibble, if m >= 2n then you need to change your "approximation" equation.  An extreme, example, is if n=1, then you need to repeat the string 8 times (i.e. perform log2(8)=3 steps).  Of course, if you *pad* with "10...0" instead of all zeros, then on average you'll have a lower error, but lose the extremes.  "However I prefer username_2's answer" :-)  Well, there's no accounting for taste 8P.  

---

