<div dir="ltr"><div><div><div><div><div><div>Thanks David, good!<br></div>I&#39;m really happy about the decision to introduce changes by small steps.<br>And we are lucky that I recently added the erf function in ArbitraryPrecisionFloat.<br>Otherwise, with 32 bits limbs, the division bug could have been un-noticed for years.<br><br></div>When I contemplate the division code, I wonder how to test such beast...<br></div>Long method, high cyclomatic complexity...<br></div><div>Given the very low probability of failure, testing with random values is not appropriate.<br></div>I wonder if some kind of formal proof would be possible.<br></div>The first thing would be to describe precisely the invariants.<br></div>If I have an occasion, I&#39;ll try to submit the case to the frama-C guys (<a href="http://frama-c.com/about.html">http://frama-c.com/about.html</a>).<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">2016-03-28 4:05 GMT+02:00 David T. Lewis <span dir="ltr">&lt;<a href="mailto:lewis@mail.msen.com" target="_blank">lewis@mail.msen.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Nicolas,<br>
<br>
I updated VMM trunk with all of your changes for LargeIntegersPlugin copied from<br>
the latest oscog branch. All number tests pass, and your ArbitraryPrecisionFloat<br>
example works properly now.<br>
<br>
Dave<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
On Mon, Mar 28, 2016 at 12:09:37AM +0200, Nicolas Cellier wrote:<br>
&gt;<br>
&gt; OK, I think I get it.<br>
&gt; The problem lies in:<br>
&gt;<br>
&gt;                 &quot;Correct overestimate of q.<br>
&gt;                 Max of 2 iterations through loop -- see Knuth vol. 2&quot;<br>
&gt;                 j &lt; 3<br>
&gt;                     ifTrue: [r3 := 0]<br>
&gt;                     ifFalse: [r3 := pRem at: j - 3].<br>
&gt;<br>
&gt;                 [(t &lt; hi<br>
&gt;                     or: [t = hi and: [r3 &lt; lo]])<br>
&gt;                     ifTrue:<br>
&gt;                         [&quot;i.e. (t,r3) &lt; (hi,lo)&quot;<br>
&gt;                         q := q - 1.<br>
&gt;                         lo &lt; dnh<br>
&gt;                             ifTrue:<br>
&gt;                                 [hi := hi - 1.<br>
&gt;                                 lo := lo + 16r100 - dnh]<br>
&gt;                             ifFalse:<br>
&gt;                                 [lo := lo - dnh].<br>
&gt;                         cond := hi &gt;= dh]<br>
&gt;                     ifFalse: [cond := false].<br>
&gt;                 cond]<br>
&gt;                     whileTrue: [hi := hi - dh]].<br>
&gt;<br>
&gt; What happens here is that hi may become negative.<br>
&gt; But since I declared it unsigned, t&lt;hi and cond := hi &gt;= dh remains false<br>
&gt; quite a long time and the quotient q is decremented way too many times...<br>
&gt;<br>
&gt; Here we divide (r1,r2,r3,...) by (dh,dnh,...)<br>
&gt; we are trying to guess q based on 2 limbs<br>
&gt; (r1,r2) = q*dh + t    that is   (r1,r2-t) = q*dh<br>
&gt; (hi,lo) =q*dnh<br>
&gt;<br>
&gt; Thus q*(dh,dnh)=(r1,r2-t+hi,lo)<br>
&gt;<br>
&gt; If t&lt;hi then q*(dh,dnh) is greater than (r1,r2) and we have an overestimate<br>
&gt; of q<br>
&gt; Same if t=hi and lo&lt;r3.<br>
&gt;<br>
&gt; Here we have the tricky case when t=0, r3=0 and lo&gt;0, and hi=dnh+1<br>
&gt; In the first loop, h gets decremented, thus hi=dnh.<br>
&gt; Then it goes to 0, and gets decremented a second time...<br>
&gt;<br>
&gt; The same algorithm is used with 32bits limbs, so it may also happen in my<br>
&gt; own VM branch. I believe it must be even rarest an event though (2^32<br>
&gt; possible values for hi makes hi=dnh+1 less probable than with 2^8<br>
&gt; combinations).<br>
&gt;<br>
&gt; I will fix it tonight or tomorrow.<br>
&gt;<br>
&gt;<br>
&gt; 2016-03-27 19:03 GMT+02:00 Nicolas Cellier &lt;<br>
&gt; <a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt;:<br>
&gt;<br>
&gt; &gt; Thanks David.<br>
&gt; &gt;<br>
&gt; &gt; By running the snippet, instrumenting erf, printing each and every<br>
&gt; &gt; intermediate value to a text file, and diffing:<br>
&gt; &gt; {<br>
&gt; &gt; (10 asArbitraryPrecisionFloatNumBits: 33) erf.<br>
&gt; &gt; (10 asArbitraryPrecisionFloatNumBits: 34) erf.<br>
&gt; &gt; }<br>
&gt; &gt;<br>
&gt; &gt; I reduced the failing test to:<br>
&gt; &gt;<br>
&gt; &gt;  a :=<br>
&gt; &gt; 1598335257761788022467377781654101148543282249044465229239888363328190330275719997501596724768507889233831388734160190922469363547795602076820594918.<br>
&gt; &gt; b := 49612.<br>
&gt; &gt; self assert: a - ((a quo: b)*b) &lt; b<br>
&gt; &gt;<br>
&gt; &gt; So it must be some nasty sign promotion (or lack of?) in division.<br>
&gt; &gt; Normally, this could be simulated, but with signedness, I&#39;m never sure,<br>
&gt; &gt; maybe my next step will be a breakpoint in xcode/gdb...<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt; Curiously, (a rem: b) is correct !<br>
&gt; &gt;<br>
&gt; &gt; 2016-03-27 17:36 GMT+02:00 David T. Lewis &lt;<a href="mailto:lewis@mail.msen.com">lewis@mail.msen.com</a>&gt;:<br>
&gt; &gt;<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; I confirm the same results for your ArbitraryPrecisionFloat example below,<br>
&gt; &gt;&gt; testing on Linux with a 64 bit interpreter VM and 32 bit image.<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt;   Image<br>
&gt; &gt;&gt;   -----<br>
&gt; &gt;&gt;   /home/lewis/squeak/Squeak4.6/squeak.37.image<br>
&gt; &gt;&gt;   Squeak4.6<br>
&gt; &gt;&gt;   latest update: #15723<br>
&gt; &gt;&gt;   Current Change Set: Unnamed2<br>
&gt; &gt;&gt;   Image format 6504 (32 bit)<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt;   Virtual Machine<br>
&gt; &gt;&gt;   ---------------<br>
&gt; &gt;&gt;   /usr/local/lib/squeak/4.15.4-3634/squeakvm<br>
&gt; &gt;&gt;   Squeak4.5 of 10 December 2015 [latest update: #1195]<br>
&gt; &gt;&gt;   Unix built on Mar 25 2016 13:27:51 Compiler: 4.9.2<br>
&gt; &gt;&gt;   platform sources revision 3634<br>
&gt; &gt;&gt;   VMMaker versionString 4.15.4<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; Dave<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; On Sun, Mar 27, 2016 at 03:25:58PM +0200, Nicolas Cellier wrote:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; Hi Levente, thank you.<br>
&gt; &gt;&gt; &gt; Here is a follow up:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; I was able to reproduce the same symptom on the classical interpreter<br>
&gt; &gt;&gt; VM.<br>
&gt; &gt;&gt; &gt; &lt;rant&gt; It&#39;s just that for MacOSX, there is no recent VM available, and<br>
&gt; &gt;&gt; that<br>
&gt; &gt;&gt; &gt; the MacOS build is somehow abandonware, so it took much more time than<br>
&gt; &gt;&gt; &gt; necessary :( &lt;/rant&gt;<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; So the changes that have been integrated on Interpreter Vm in july 2014<br>
&gt; &gt;&gt; and<br>
&gt; &gt;&gt; &gt; that I thought correct were not.<br>
&gt; &gt;&gt; &gt; It&#39;s certainly related to a LargeInteger plugin primitive.<br>
&gt; &gt;&gt; &gt; Those are triggered when nbits of magnitude &gt; 64.<br>
&gt; &gt;&gt; &gt; (otherwise, &lt;= 64 bits, the LargeInteger numbered primitives do their<br>
&gt; &gt;&gt; job).<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; Now the job is to produce/isolate an elementary failing LargeInteger<br>
&gt; &gt;&gt; test.<br>
&gt; &gt;&gt; &gt; But you need to generate the VM from VMMaker.oscog head for COG/STACK<br>
&gt; &gt;&gt; &gt; V3/SPUR 32/64 bits<br>
&gt; &gt;&gt; &gt; or use a sufficiently recent interpreter VM (&gt; july 2014) to trigger<br>
&gt; &gt;&gt; such<br>
&gt; &gt;&gt; &gt; failure.<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; --------------------------------------------<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; Here is my starting point:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; If you load ArbitraryPrecisionFloat and Tests from<br>
&gt; &gt;&gt; &gt; <a href="http://www.squeaksource.com/ArbitraryPrecisionFl" rel="noreferrer" target="_blank">http://www.squeaksource.com/ArbitraryPrecisionFl</a><br>
&gt; &gt;&gt; &gt; then you&#39;ll see this strange pattern:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; (53 to: 70) collect: [:i |<br>
&gt; &gt;&gt; &gt;     i -&gt; (10 asArbitraryPrecisionFloatNumBits: i) erf ]<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt;  {53-&gt;(ArbitraryPrecisionFloat readFrom: &#39;0.9999998981732067&#39; readStream<br>
&gt; &gt;&gt; &gt; numBits: 53) .<br>
&gt; &gt;&gt; &gt;  54-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 54) .<br>
&gt; &gt;&gt; &gt;  55-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 55) .<br>
&gt; &gt;&gt; &gt;  56-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 56) .<br>
&gt; &gt;&gt; &gt;  57-&gt;(ArbitraryPrecisionFloat readFrom: &#39;0.99999989817320666&#39; readStream<br>
&gt; &gt;&gt; &gt; numBits: 57) .<br>
&gt; &gt;&gt; &gt;  58-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 58) .<br>
&gt; &gt;&gt; &gt;  59-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 59) .<br>
&gt; &gt;&gt; &gt;  60-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 60) .<br>
&gt; &gt;&gt; &gt;  61-&gt;(ArbitraryPrecisionFloat readFrom: &#39;0.9999998981732066655&#39;<br>
&gt; &gt;&gt; readStream<br>
&gt; &gt;&gt; &gt; numBits: 61) .<br>
&gt; &gt;&gt; &gt;  62-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 62) .<br>
&gt; &gt;&gt; &gt;  63-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 63) .<br>
&gt; &gt;&gt; &gt;  64-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 64) .<br>
&gt; &gt;&gt; &gt;  65-&gt;(ArbitraryPrecisionFloat readFrom: &#39;0.99999989817320666564&#39;<br>
&gt; &gt;&gt; readStream<br>
&gt; &gt;&gt; &gt; numBits: 65) .<br>
&gt; &gt;&gt; &gt;  66-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 66) .<br>
&gt; &gt;&gt; &gt;  67-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 67) .<br>
&gt; &gt;&gt; &gt;  68-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 68) .<br>
&gt; &gt;&gt; &gt;  69-&gt;(ArbitraryPrecisionFloat readFrom: &#39;0.999999898173206665646&#39;<br>
&gt; &gt;&gt; &gt; readStream numBits: 69) .<br>
&gt; &gt;&gt; &gt;  70-&gt;(ArbitraryPrecisionFloat readFrom: &#39;1.0&#39; readStream numBits: 70)}<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; The value seems incorrect every four numbits<br>
&gt; &gt;&gt; &gt; The exact value is near 1- 2.0e-45, and given the insufficient precision<br>
&gt; &gt;&gt; &gt; requested, the result should be rounded to 1.<br>
&gt; &gt;&gt; &gt; We can confirm with online high precision erf calculator like found for<br>
&gt; &gt;&gt; &gt; example with <a href="http://keisan.casio.com/exec/system/1180573449" rel="noreferrer" target="_blank">http://keisan.casio.com/exec/system/1180573449</a><br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; Or we can check with<br>
&gt; &gt;&gt; &gt; (10 asArbitraryPrecisionFloatNumBits: 200) erf (ArbitraryPrecisionFloat<br>
&gt; &gt;&gt; &gt; readFrom:<br>
&gt; &gt;&gt; &#39;0.999999999999999999999999999999999999999999997911512416237455&#39;<br>
&gt; &gt;&gt; &gt; readStream numBits: 200)<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; -----------------------------<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; Note that when I change the LargeInteger digitLength to 32bits instead<br>
&gt; &gt;&gt; of 8<br>
&gt; &gt;&gt; &gt; (my own VM branch) then the problem magically disappear.<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; I plan to introduce these change in the VMMaker.oscog, so I can as well<br>
&gt; &gt;&gt; &gt; ignore the problem and proceed, however I much prefer to isolate it, and<br>
&gt; &gt;&gt; &gt; understand it for gain of knowledge :)<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; 2016-03-27 4:27 GMT+02:00 Levente Uzonyi &lt;<a href="mailto:leves@caesar.elte.hu">leves@caesar.elte.hu</a>&gt;:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; &gt;<br>
&gt; &gt;&gt; &gt; &gt; Hi Nicolas,<br>
&gt; &gt;&gt; &gt; &gt;<br>
&gt; &gt;&gt; &gt; &gt; If you give us a bit more detailed instructions about what to test,<br>
&gt; &gt;&gt; then<br>
&gt; &gt;&gt; &gt; &gt; we might be able to help you get this sorted out.<br>
&gt; &gt;&gt; &gt; &gt;<br>
&gt; &gt;&gt; &gt; &gt; Levente<br>
&gt; &gt;&gt; &gt; &gt;<br>
&gt; &gt;&gt; &gt; &gt;<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt;<br>
&gt; &gt;<br>
<br>
</div></div></blockquote></div><br></div>