<div dir="ltr">Hi Chris,<br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Dec 23, 2014 at 12:50 PM, Chris Muller <span dir="ltr">&lt;<a href="mailto:asqueaker@gmail.com" target="_blank">asqueaker@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=""><div class="h5">On Mon, Dec 22, 2014 at 3:59 AM, Bert Freudenberg &lt;<a href="mailto:bert@freudenbergs.de">bert@freudenbergs.de</a>&gt; wrote:<br>
&gt; On 22.12.2014, at 00:13, Levente Uzonyi &lt;<a href="mailto:leves@elte.hu">leves@elte.hu</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; ConverterFloatArray at: 1 put: self; basicAt: 1.<br>
&gt;<br>
&gt; Any reason not to use this in #asIEEE32BitWord? Endianness? Arch-dependency?<br>
&gt;<br>
&gt; I see, it&#39;s not thread-safe. This would be:<br>
&gt;<br>
&gt;         (FloatArray new: 1) at: 1 put: self; basicAt: 1.<br>
&gt;<br>
&gt; Might still be faster?<br>
<br>
</div></div>Yes.  Since creation of a one-element FloatArray every time did not<br>
adversely affect performance of Levente&#39;s too significantly (only 3.7X<br>
instead of 4.0X faster), I decided it was worth the cost of the<br>
allocation than to worry about concurrency.  So I ended up with<br>
Levente&#39;s latest except I cannot risk a calculation ending up -0.0, so<br>
I have to account for it too.  And, NaN too.  Thus:<br>
<br>
     hashKey32<br>
          | bits |<br>
          self = NegativeInfinity ifTrue: [ ^ 0 ].<br>
          self = Infinity ifTrue: [ ^ 4294967294 ].<br>
          self = NaN ifTrue: [ ^ 4294967295 ].<br>
          self = NegativeZero ifTrue: [ ^ 2147483651 ].<br>
          bits := (FloatArray new: 1) at: 1 put: self; basicAt: 1.<br>
          self &lt; 0.0 ifTrue: [ ^ 4286578688 - bits ].<br>
          ^ 2147483651 + bits<br></blockquote><div><br></div><div>FloatArray basicNew: 1 will be a little bit faster.  Please use hex to make the layout clear.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
Since there are not a full 32-bits worth of IEEE 32-bit floats (e.g.,<br>
several thousand convert to NaN), it might be wise to move +Infinity<br>
and NaN _down_ a bit from the very maximum, for better continuity<br>
between the float and integer number lines, or for potential future<br>
special-case needs..?<br>
<br>
In any case, I wanted to at least see if what we have, above, works<br>
for every 32-bit IEEE float.  To verify that, I enumerated all Floats<br>
in numerical order from -Infinity to +Infinity by creating them via<br>
#fromIEEE32BitFloat: from the appropriate ranges.<br>
<br>
It hit a snag at 2151677948.  Check this out:<br>
<br>
     | this next |<br>
     this := Float fromIEEE32Bit: 2151677949.<br>
     next := Float fromIEEE32Bit: 2151677948.<br>
     self<br>
          assert: next &gt; this ;<br>
          assert: ((FloatArray new: 1) at: 1 put: (next); basicAt: 1)<br>
&gt; ((FloatArray new: 1) at: 1 put: (this); basicAt: 1)<br>
<br>
As I thought, the representations between IEEE floats and FloatArray<br>
floats are different-enough that their precisions align differently<br>
onto the 32-bit map for these two floats.  IEEE&#39;s are precise-enough<br>
to distinguish these two floats, FloatArray representations are not.<br></blockquote><div><br></div><div>Chris, FloatArray stores 32-bit ieee 754 single-precision floats, Float represents 64-bit ieee 754 double-precision floats.  They look like this:</div><div><br></div><div>single-precision: sign, 8-bit exponent, 23 bit mantissa</div><div>double-precision: sign, 11-bit exponent, 52 bit mantissa<br></div><div><br></div><div>So if you assign a large Float to a Float array it will map to Infinity:</div><div><br></div><div>((FloatArray new: 1) at: 1 put: 1.0e238; at: 1) =&gt; Infinity<br></div><div><br></div><div>and if you assign a small one it will map to zero:</div><div><div><br></div><div>((FloatArray new: 1) at: 1 put: 1.0e-238; at: 1) =&gt; 0.0</div></div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">That these guys are considered &quot;equal&quot; by the FloatArray is actually<br>
good enough for my indexing requirement, but now I&#39;m looking at the<br>
prim-fail code for FloatArray:<br>
<br>
    at: index<br>
         &lt;primitive: &#39;primitiveAt&#39; module: &#39;FloatArrayPlugin&#39;&gt;<br>
          ^Float fromIEEE32Bit: (self basicAt: index)<br>
<br>
If this or the #at:put: primitive were to ever fail on the storage<br>
(at:put:) exclusive-or the access (at:) side, then it appears<br>
FloatArray itself would retrieve a value different than was stored..!<br></blockquote><div><br></div><div>But that happens whenever you store a double that cannot be represented as a 32-bit float.  That;s exactly what we&#39;re doing here is mapping 64-bit floats to 32-bit floats so we expect to retrieve different values than those stored most of the time, on average 2^32-1/(2^32).  Only 1/(2^32) of the double precision floats are exactly representable in 32-bits. </div></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">best,<div>Eliot</div></div>
</div></div>