<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <title>P0811R0: Well-behaved interpolation for numbers and pointers</title>
  <style type="text/css">
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
  margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #40a070; }
code > span.fl { color: #40a070; }
code > span.ch { color: #4070a0; }
code > span.st { color: #4070a0; }
code > span.co { color: #60a0b0; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #06287e; }
code > span.er { color: #ff0000; font-weight: bold; }
  </style>
</head>
<body>
<div id="header">
<h1 class="title">P0811R0: Well-behaved interpolation for numbers and pointers</h1>
</div>
<p><em>Audience</em>: SG6; WG14<br />S. Davis Herring &lt;<script type="text/javascript">
<!--
h='&#108;&#x61;&#110;&#108;&#46;&#x67;&#x6f;&#118;';a='&#64;';n='&#104;&#x65;&#114;&#114;&#x69;&#110;&#x67;';e=n+a+h;
document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+'<code>'+e+'</code>'+'<\/'+'a'+'>');
// -->
</script><noscript>&#104;&#x65;&#114;&#114;&#x69;&#110;&#x67;&#32;&#x61;&#116;&#32;&#108;&#x61;&#110;&#108;&#32;&#100;&#x6f;&#116;&#32;&#x67;&#x6f;&#118;</noscript>&gt;<br />Los Alamos National Laboratory<br />October 16, 2017</p>
<h1 id="introduction">Introduction</h1>
<p>The simple problem of computing a value between two other values is surprisingly subtle in general. This paper proposes library functions to compute the midpoint between two integer, floating-point, or pointer values, as well as a more general routine that interpolates (or extrapolates) between two floating-point values.</p>
<p>These utilities are a pure library extension. With the exception of the pointer versions, they would be valuable and straightforward to implement in C (perhaps via type-generic macros); it would be appropriate to consult with WG14 about including them in the C standard library.</p>
<h1 id="midpoint">Midpoint</h1>
<h2 id="integers">Integers</h2>
<p>Computing the (integer) midpoint of two integer values via</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">(a+b)/<span class="dv">2</span></code></pre>
<p>can cause overflow for signed or unsigned integers as well as for floating-point values. <a href="https://research.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html">Java's binary search implementation</a> had this integer overflow bug for nearly a decade, and Mozilla had <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=917841">the same issue</a> in its JavaScript implementation.</p>
<p>The standard alternative</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">a+(b-a)/<span class="dv">2</span></code></pre>
<p>works for unsigned integers (even if <code>b&lt;a</code>). On a typical two's complement implementation where conversion from unsigned to signed preserves bit patterns, the library can provide the simple implementation</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">Integer mid(Integer a, Integer b) {
  <span class="kw">using</span> U = make_unsigned_t&lt;Integer&gt;;
  <span class="kw">return</span> Integer(U(a)+(U(b)-U(a))/<span class="dv">2</span>);
}</code></pre>
<p>that works for signed or unsigned <code>Integer</code>. Note that when <code>b==a+1</code> or <code>b==a-1</code> (without overflow), the result is <em>a</em> because of truncating division. This can be exploited to round half-integers up or down by supplying <code>a&gt;=b</code> or <code>a&lt;=b</code> respectively. (The simple <code>(a+b)/2</code> always truncates half-integers towards 0, yielding <code>min(a,b)</code> when they differ by 1.)</p>
<h2 id="pointers">Pointers</h2>
<p>When a binary search over an array is implemented using pointers, the array size must not exceed <code>PTRDIFF_MAX</code> to avoid undefined behavior ([expr.add]/5). The library can also provide a function template</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span>&lt;<span class="kw">class</span> T&gt;
T* mid(T *a, T *b);</code></pre>
<p>which is straightforward on common architectures but, it seems, <strong>cannot be implemented</strong> portably and efficiently in cpp. As with integers, when the midpoint lies between two pointer values the one closer to <code>a</code> is chosen; for the usual case of <code>a&lt;b</code>, this is compatible with the usual half-open ranges by selecting <code>a</code> when <code>[a,b)</code> is <code>[a,a+1)</code>.</p>
<h2 id="floating-point-types">Floating-point types</h2>
<p>Each of the midpoint formulas above can cause overflow for floating-point types; the latter can also produce results that are not correctly rounded (by rounding in the subtraction and the addition). A third choice</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">a/<span class="dv">2</span>+b/<span class="dv">2</span></code></pre>
<p>prevents overflow but is not correctly rounded for subnormal inputs (due to rounding each separately). The library can easily provide overloads of <code>mid</code> for floating-point types that is correctly rounded for all inputs by switching between these strategies:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">Float mid(Float a, Float b)
{<span class="kw">return</span> isnormal(a) &amp;&amp; isnormal(b) ? a/<span class="dv">2</span>+b/<span class="dv">2</span> : (a+b)/<span class="dv">2</span>;}</code></pre>
<h2 id="naming">Naming</h2>
<p>The name <code>mean</code> is superior for the floating-point case, but for the other types (and the common application to binary search) the name <code>mid</code> used above is more appropriate. It would be possible to use both names (despite the possible confusion with the use of <code>mean</code> in [rand.dist]), but as it aims to replace the simple expression <code>(a+b)/2</code> regardless of type, a single name seems best.</p>
<h1 id="linear-interpolation">Linear interpolation</h1>
<p>Both <a href="https://stackoverflow.com/questions/4353525/floating-point-linear-interpolation">obvious approaches</a> used in published implementations of floating-point linear interpolation have <a href="https://math.stackexchange.com/questions/907327/accurate-floating-point-linear-interpolation">issues</a>:</p>
<ol style="list-style-type: decimal">
<li><code>a+t*(b-a)</code> does not in general reproduce <em>b</em> when <code>t==1</code>, and can overflow if <em>a</em> and <em>b</em> have the largest exponent and opposite signs.</li>
<li><code>t*b+(1-t)*a</code> is not monotonic in general (unless <code>a*b&lt;=0</code>).</li>
</ol>
<p>Lacking an obvious, efficient means of obtaining a correctly rounded overall result, the goal is instead to guarantee the basic properties of</p>
<ol style="list-style-type: decimal">
<li><em>exactness</em>: <code>lint(a,b,0)==a &amp;&amp; lint(a,b,1)==b</code></li>
<li><em>monotonicity</em>: <code>(lint(a,b,t2)-lint(a,b,t1)) * (t2-t1) * (b-a) &gt;= 0</code></li>
<li><em>boundedness</em>: <code>t&lt;0 || t&gt;1 || isfinite(lint(a,b,t))</code></li>
<li><em>consistency</em>: <code>lint(a,a,t)==a</code></li>
</ol>
<p>given that each argument <code>isfinite</code> (for monotonicity, <em>t1</em> and <em>t2</em> may also be infinite if <code>a!=b</code>). These properties are useful in proofs of correctness of algorithms based on <code>lint</code>. When interpolating, consistency follows from the other properties, but it and monotonicity apply even when extrapolating.</p>
<p>To demonstrate the feasibility of satisfying these properties, a simple implementation that provides all of them is given here:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">Float lint(Float a, Float b, Float t) {
  <span class="co">// Exact, monotonic, bounded, and (for a=b=0) consistent:</span>
  <span class="kw">if</span>(a*b &lt;= <span class="dv">0</span>) <span class="kw">return</span> t*b + (<span class="dv">1</span>-t)*a;

  <span class="kw">if</span>(t==<span class="dv">1</span>) <span class="kw">return</span> b;                        <span class="co">// exact</span>
  <span class="co">// Exact at t=0, monotonic except near t=1, bounded, and consistent:</span>
  <span class="dt">const</span> Float x = a + t*(b-a);
  <span class="kw">return</span> t&gt;<span class="dv">1</span> == b&gt;a ? max(b,x) : min(b,x);  <span class="co">// monotonic near t=1</span>
}</code></pre>
<p>Putting <code>b</code> first in the <code>min</code>/<code>max</code> prefers it to another equal value (i.e., <code>-0.</code> vs. <code>+0.</code>), which avoids returning <code>-0.</code> for <code>t==1</code> but <code>+0.</code> for other nearby values of <em>t</em>.</p>
<p>Whether it uses this implementation or not, the library can provide a function satisfying these mathematical properties.</p>
<h2 id="naming-1">Naming</h2>
<p>The name <code>lerp</code> is commonly seen in the context of <a href="https://msdn.microsoft.com/en-us/library/microsoft.xna.framework.mathhelper.lerp.aspx">computer graphics</a>, <a href="https://github.com/mattdesl/lerp/blob/master/index.js">among other places</a>. It is also sometimes called <a href="https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/mix.xhtml"><code>mix</code></a>, but that name seems too generic. The name <code>lint</code> is associated with <a href="https://www.ibm.com/support/knowledgecenter/en/SSLVMB_20.0.0/com.ibm.spss.statistics.help/alg_rmv_linear.htm">sampling between list elements</a>; since it is the clearest abbreviation of <strong>l</strong>inear <strong>int</strong>erpolation, it is used here.</p>
<p>It would also be possible to make this function yet another overload of <code>mid</code>, but that would even more strongly imply a restriction to interpolation.</p>
</body>
</html>
