<div dir="ltr">On Wed, Oct 25, 2017 at 9:05 PM, David Zarzycki <span dir="ltr">&lt;<a href="mailto:dave@znu.io" target="_blank">dave@znu.io</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><br><div><span class=""><br><blockquote type="cite"><div>On Oct 25, 2017, at 19:25, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:</div><div><div dir="ltr"><br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div>I was proposing something different where Float and Int are both Equatable and Substitutable, but neither Equatable nor Substitutable inherit from the other. The former is mathematical and the latter is not (which allows it to deal with NaN payloads, ±0, etc). Generic algorithms care mostly if not completely about mathematics, while generic containers care mostly if not completely about substitutability. They can live alongside each other and get along peacefully/sanely. And if people need to care about both, then at least they have an out.</div></div></blockquote><div><br></div>The issue with this is similar to that in my reply earlier about bitwise comparison of floating-point values. Yes, you can propose some total ordering over floating-point values totally divorced from `==`, but I&#39;m quite certain that people who invoke `sort()` on an array of floating-point values don&#39;t simply want *some* deterministic order, but rather an actual increasing order of numeric values.</div></div></div></div></blockquote><div><br></div></span>Hi Xiaodi,</div><div><br></div><div>Of course, and the implementors of floating point data types would be expected to do just that. It isn’t hard. For example, in C:</div><div><br></div><div><font face="Courier">// Make floats sort reliably and sufficiently reasonably</font></div><div><font face="Courier">bool sortableLessThan(float x,<wbr> float y) {<br>  union {<br>    int i;<br>    float f;<br>  } ux = { .f = x }, uy = { .f = y };<br>  int high_bit = ~INT_MAX;<br>  int x2 = ux.i &gt;= 0 ? ux.i : (~ux.i | high_bit);<br>  int y2 = uy.i &gt;= 0 ? uy.i : (~uy.i | high_bit);<br>  return x2 &lt; y2;<br>}<br></font><br></div><div>Which the compiler vectorizes down to the following branchless code (which is debatably “reasonable” for sorting):</div><div><br></div><div>c.o`sortableLessThan:<br>c.o[0x0] &lt;+0&gt;:   vinsertps $0x10, %xmm1, %xmm0, %xmm0 ; xmm0 = xmm0[0],xmm1[0],xmm0[2,3] <br>c.o[0x6] &lt;+6&gt;:   vmovlps %xmm0, -0x8(%rsp)<br>c.o[0xc] &lt;+12&gt;:  vpmovsxdq -0x8(%rsp), %xmm0<br>c.o[0x13] &lt;+19&gt;: vpcmpeqd %xmm1, %xmm1, %xmm1<br>c.o[0x17] &lt;+23&gt;: vpcmpgtq %xmm1, %xmm0, %xmm1<br>c.o[0x1c] &lt;+28&gt;: vpor   0x2c(%rip), %xmm0, %xmm2<br>c.o[0x24] &lt;+36&gt;: vpxor  0x34(%rip), %xmm2, %xmm2  ; (uint128_t) 0x00007fffffff000000007fffffff<wbr>0000<br>c.o[0x2c] &lt;+44&gt;: vblendvpd %xmm1, %xmm0, %xmm2, %xmm0<br>c.o[0x32] &lt;+50&gt;: vmovd  %xmm0, %eax<br>c.o[0x36] &lt;+54&gt;: vpextrd $0x2, %xmm0, %ecx<br>c.o[0x3c] &lt;+60&gt;: cmpl   %ecx, %eax<br>c.o[0x3e] &lt;+62&gt;: setl   %al<br>c.o[0x41] &lt;+65&gt;: retq   <br></div></div></blockquote><div><br></div><div>We already have a similar function in Swift (`isTotallyOrdered`) which complies with IEEE requirements for total order, and we do not need to invent another such algorithm.</div><div><br></div><div>As I have said, the same approach is not useful for what you call &quot;substitutability.&quot; What useful generic algorithms can be written that make use of the bitwise _equality_ of two floating-point values?<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div></div><div><br></div><div><span class=""><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"> Likewise, when someone asks if an array contains a floating-point value (say, `10.0 as Decimal`), they generally want to know if *any* representation of that value exists.</div></div></div></div></blockquote><div><br></div></span><div>I’ve been thinking about the “contains” API argument a lot today, and I’m of the opinion now that we’re arguing about a problem that doesn’t exist.</div><div><br></div><div>The “contains” question doesn’t make sense because of rounding errors that are inherent in floating point arithmetic. People would need to write “.contains(value: x, plusOrMinus: y)” and there is no way that the generic collection types are going to vend such an API. If anything, the “contains” API needs to be limited to types that conform to (hand waving) some kind of “PreciseValue” protocol (which floating point would not). For the exact same rounding-error reasons, I don’t think floating point types should be hashable either.</div></div></div></blockquote><div><br></div><div>This is looking at it backwards. Collection vends a &quot;contains&quot; method and it must do something for floating-point values. It would be exceedingly user hostile to have it compare values bitwise. If people want to account for rounding errors, there&#39;s `contains(where:)`, but it is entirely legitimate to ask whether a collection contains exactly zero, exactly infinity, or any of a variety of exactly representable values.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div><span class=""><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">The point is that _what kind of substitutability_ matters, and the kind that people will expect for floating-point values is the very mathematical substitutability that is supposed to be guaranteed by Equatable, which simply does not accommodate NaN.</div></div></div></div></blockquote></span></div><div><br></div><div>Given that rounding errors make “contains” and “hashing” impractical to use with floating point types, I don’t see any holes with my (hand waving) “Substitutability” proposal. I could be missing something though. Can you think of anything?</div></div></blockquote><div><br></div><div>By your argument, every generic use of `==` is impractical for floating-point types. If you believe, then, that you don&#39;t need to consider how these &quot;impractical&quot; APIs on Collection work with floating-point types because they shouldn&#39;t be used in the first place, then why bother to make any changes at all to the semantics of `Equatable`? The only changes we&#39;re talking about here are to do with how these &quot;impractical&quot; APIs behave.</div><div><br></div></div></div></div>