title: A fast method to round a double to a 32-bit int explained
body: <p>When reading <a href="http://en.wikipedia.org/wiki/Lua_%28programming_language%29" rel="nofollow noreferrer">Lua</a>’s source code, I noticed that Lua uses a macro to round <code>double</code> values to 32-bit <code>int</code> values. The macro is defined in the <a href="http://www.lua.org/source/5.2/llimits.h.html" rel="nofollow noreferrer"><code>Llimits.h</code> header file</a> and reads as follows:</p>
  <pre><code>union i_cast {double d; int i[2]};
  #define double2int(i, d, t) \
      {volatile union i_cast u; u.d = (d) + 6755399441055744.0; \
      (i) = (t)u.i[ENDIANLOC];}
  </code></pre>
  <p>Here <code>ENDIANLOC</code> is defined according to <a href="http://en.wikipedia.org/wiki/Endianness" rel="nofollow noreferrer">endianness</a>: 0 for little endian, 1 for big endian architectures; Lua carefully handles endianness. The <code>t</code> argument is substituted with an integer type like <code>int</code> or <code>unsigned int</code>.</p>
  <p>I did a little research and found that there is a simpler format of that macro which uses the same technique:</p>
  <pre><code>#define double2int(i, d) \
      {double t = ((d) + 6755399441055744.0); i = *((int *)(&amp;t));}
  </code></pre>
  <p>Or, in a C++-style:</p>
  <pre><code>inline int double2int(double d)
  {
      d += 6755399441055744.0;
      return reinterpret_cast&lt;int&amp;&gt;(d);
  }
  </code></pre>
  <p>This trick can work on any machine using <a href="https://en.wikipedia.org/wiki/IEEE_floating_point" rel="nofollow noreferrer">IEEE 754</a> (which means pretty much every machine today). It works for both positive and negative numbers, and the rounding follows <a href="https://en.wikipedia.org/wiki/Rounding#Round_half_to_even" rel="nofollow noreferrer">Banker’s Rule</a>. (This is not surprising, since it follows IEEE 754.)</p>
  <p>I wrote a little program to test it:</p>
  <pre><code>int main()
  {
      double d = -12345678.9;
      int i;
      double2int(i, d)
      printf(&quot;%d\n&quot;, i);
      return 0;
  }
  </code></pre>
  <p>And it outputs <code>-12345679</code>, as expected.</p>
  <p>I would like to understand how this tricky macro works in detail. The magic number <code>6755399441055744.0</code> is actually 2<sup>51</sup> + 2<sup>52</sup>, or 1.5 × 2<sup>52</sup>, and 1.5 in binary can be represented as 1.1. When any 32-bit integer is added to this magic number—</p>
  <p>Well, I’m lost from here. <strong>How does this trick work?</strong></p>
  <h3>Update</h3>
  <ol>
  <li><p>As @Mysticial points out, this method does not limit itself to a 32-bit <code>int</code>, it can also be expanded to a 64-bit <code>int</code> as long as the number is in the range of 2<sup>52</sup>. (Although the macro needs some modification.)</p>
  </li>
  <li><p>Some materials say this method cannot be used in <a href="http://en.wikipedia.org/wiki/Microsoft_Direct3D" rel="nofollow noreferrer">Direct3D</a>.</p>
  </li>
  <li><p>When working with Microsoft assembler for x86, there is an even faster macro written in assembly code (the following is also extracted from Lua source):</p>
  <pre><code> #define double2int(i,n)  __asm {__asm fld n   __asm fistp i}
  </code></pre>
  </li>
  <li><p>There is a similar magic number for single precision numbers: 1.5 × 2<sup>23</sup>.</p>
  </li>
  </ol>