<div dir="ltr">Okay, this should work faster.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El mié., 9 oct. 2019 a las 1:22, Andres Valloud via Cuis-dev (<<a href="mailto:cuis-dev@lists.cuis.st">cuis-dev@lists.cuis.st</a>>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">In the larger slicer test,<br>
<br>
slicer := 1024.<br>
thickness := 255.<br>
maxK := 1 bitShift: 32.<br>
integers := 1 to: maxK by: maxK // slicer<br>
        :: inject: OrderedCollection new<br>
        into: [:t :x | t add: x.  thickness timesRepeat: [t add: t last + 1]. <br>
t yourself]<br>
                :: asArray.<br>
Time millisecondsToRun: [1 to: integers size do: [:x | (integers at: x) <br>
isPrimeFast2e]]<br>
<br>
I get 2627 vs 2430, or about 7.5% faster.<br>
<br>
On 10/8/19 21:19, Andres Valloud via Cuis-dev wrote:<br>
> "The latest code you sent"<br>
> Time millisecondsToRun:<br>
>      [10000 timesRepeat: [1 to: 1000 do: [:x | x isPrimeFast1b]]] 767<br>
> <br>
> "The code from my last email"<br>
> Time millisecondsToRun:<br>
>      [10000 timesRepeat: [1 to: 1000 do: [:x | x isPrimeFast2e]]] 704<br>
> <br>
> The observation is that the boundary of 31 is arbitrary, so we might as <br>
> well tune it according to the break even point.<br>
> <br>
> On 10/8/19 21:11, Agustín Sansone via Cuis-dev wrote:<br>
>> I don't think there will be any difference by making optimizations for <br>
>> small numbers. This runs just as fast as the original approach.<br>
>><br>
>> El mié., 9 oct. 2019 a las 1:01, Andres Valloud via Cuis-dev <br>
>> (<<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>>>) escribió:<br>
>><br>
>>     Expanding on the idea to treat tiny integers as special cases,<br>
>>     approximating sqrtFloor for tiny integers wins.<br>
>><br>
>>     On 10/8/19 20:49, Andres Valloud via Cuis-dev wrote:<br>
>>      > See attached hybrid.<br>
>>      ><br>
>>      > On 10/8/19 20:44, Andres Valloud via Cuis-dev wrote:<br>
>>      >> Right, that won't work.  I had tried to avoid doing something<br>
>>     like this,<br>
>>      >><br>
>>      >>      | mod30Index |<br>
>>      >>      self < 3 ifTrue: [^self = 2].<br>
>>      >>      self < 32 ifTrue: [<br>
>>      >>          ^#(false true true false true false true false false <br>
>> false<br>
>>      >>              true false true false false false true false true <br>
>> false<br>
>>      >>              false false true false false false false false true<br>
>>     false<br>
>>      >>              true) at: self].<br>
>>      >>      mod30Index := self \\ 30 + 1.<br>
>>      >>      #(false true false false false false false true false false<br>
>>      >>          false true false true false false false true false true<br>
>>      >>          false false false true false false false false false <br>
>> true)<br>
>>      >>              at: mod30Index :: ifFalse: [^false].<br>
>>      >><br>
>>      >><br>
>>      >> but alas it's not as simple as I thought.<br>
>>      >><br>
>>      >> Andres.<br>
>>      >><br>
>>      >> On 10/8/19 20:40, Agustín Sansone via Cuis-dev wrote:<br>
>>      >>> Sorry, I think this does not work for the numbers 3, 5, 7, <br>
>> 11, 13,<br>
>>      >>> 17, 19, 23, 29 and 31.<br>
>>      >>><br>
>>      >>> El mié., 9 oct. 2019 a las 0:34, Andres Valloud via Cuis-dev<br>
>>      >>> (<<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>><br>
>>     <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>>>>)<br>
>>     escribió:<br>
>>      >>><br>
>>      >>>     I played a bit with the guard clauses and found the<br>
>>     attached one is<br>
>>      >>>     simpler yet just as fast.<br>
>>      >>><br>
>>      >>>     On 10/8/19 20:11, Andres Valloud via Cuis-dev wrote:<br>
>>      >>>      > Regarding each+31, sure, 30*k+1 comes first, except when<br>
>>     k = 0<br>
>>      >>>     because<br>
>>      >>>      > why would anyone try dividing by 1.  So this is why that<br>
>>     case is<br>
>>      >>>     shifted<br>
>>      >>>      > by 30.  However, when written this way, the actual <br>
>> divisor<br>
>>      >>>     evaluation<br>
>>      >>>      > order is 31, 7, 11, and so on.  It's more likely that a<br>
>>     random<br>
>>      >>>     integer<br>
>>      >>>      > is 0 mod 7 than 0 mod 31, and the sooner one detects <br>
>> exact<br>
>>      >>>     division, the<br>
>>      >>>      > sooner the computation can stop.  Because of that, I<br>
>>     think the<br>
>>      >>>     each+31<br>
>>      >>>      > case should be the last one in the division loop.<br>
>>      >>>      ><br>
>>      >>>      > On 10/8/19 19:17, Agustín Sansone via Cuis-dev wrote:<br>
>>      >>>      >> Hello!<br>
>>      >>>      >><br>
>>      >>>      >> I agree with you. I don't think isPrime should send<br>
>>      >>> isProbablyPrime<br>
>>      >>>      >> because it could fail in the future.<br>
>>      >>>      >> I leave you here the implementation with this<br>
>>     taken care of.<br>
>>      >>>      >> I wrote the (each+31) case first in the trial division<br>
>>     loop,<br>
>>      >>>     because<br>
>>      >>>      >> it is testing the 30*k+1 case, wich I also wrote first<br>
>>     in the<br>
>>      >>>     comment.<br>
>>      >>>      >><br>
>>      >>>      >> Thanks,<br>
>>      >>>      >> Agustín<br>
>>      >>>      >><br>
>>      >>>      >> El mar., 8 oct. 2019 a las 8:11, Juan Vuletich via <br>
>> Cuis-dev<br>
>>      >>>      >> (<<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a><br>
>>     <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>> <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a><br>
>>     <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>>><br>
>>      >>>     <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a><br>
>>     <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>> <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a><br>
>>     <mailto:<a href="mailto:cuis-dev@lists.cuis.st" target="_blank">cuis-dev@lists.cuis.st</a>>>>>)<br>
>>      >>>     escribió:<br>
>>      >>>      >><br>
>>      >>>      >>     Hi Folks,<br>
>>      >>>      >><br>
>>      >>>      >>     I agree with Andrés comments, and will just<br>
>>     focusing on the<br>
>>      >>>     proposed<br>
>>      >>>      >>     changes.<br>
>>      >>>      >>     (snip)<br>
>>      >>>      >><br>
>>      >>>      >>     On 10/8/2019 2:20 AM, Andres Valloud via Cuis-dev<br>
>>     wrote:<br>
>>      >>>      >>      > Agustin, nice to see someone looking into these<br>
>>     kinds of<br>
>>      >>>     things<br>
>>      >>>      >> :).<br>
>>      >>>      >>      > ...<br>
>>      >>>      >>      >>   * The *raisedToInteger: exp modulo: m <br>
>> *method**in<br>
>>      >>>     Integer has<br>
>>      >>>      >>     a very<br>
>>      >>>      >>      >>     big problem. If we compute, for example, /"5<br>
>>      >>>     raisedTo: 0<br>
>>      >>>      >> modulo:<br>
>>      >>>      >>      >>     0"/, this returns 1. This means, that<br>
>>     according to<br>
>>      >>>      >>     Smalltalk, the<br>
>>      >>>      >>      >>     rest of the division by 0 of 1(=5^0) is<br>
>>     equal to<br>
>>      >>> 1 (Yes,<br>
>>      >>>      >>     division by<br>
>>      >>>      >>      >>     zero!!). I think you can see the problem.<br>
>>     This is<br>
>>      >>>     due the<br>
>>      >>>      >>     first line<br>
>>      >>>      >>      >>     of the method, that says /"(exp = 0) <br>
>> ifTrue: [^<br>
>>      >>>     1].", /does<br>
>>      >>>      >>      >>     not check anything else. This problem can<br>
>>     be easily<br>
>>      >>>     fixed by<br>
>>      >>>      >>      >>     checking if m=0 just before.<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > I agree, the current code appears to be <br>
>> wrong.  The<br>
>>      >>>     initials on<br>
>>      >>>      >> the<br>
>>      >>>      >>      > code belong to Juan Vuletich and Nicolas<br>
>>     Cellier.  Guys,<br>
>>      >>>     is there<br>
>>      >>>      >>      > reason why e.g. 5 raisedTo: 0 modulo: 0 should<br>
>>     answer 1<br>
>>      >>>     rather<br>
>>      >>>      >> than<br>
>>      >>>      >>      > fail?  I don't see any, but...<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > Assuming the code is broken and needs to be <br>
>> fixed,<br>
>>      >>>      >> alternatively one<br>
>>      >>>      >>      > could also write the initial guard clause like <br>
>> this:<br>
>>      >>>      >>      ><br>
>>      >>>      >>      >     n = 0 ifTrue: [^1 \\ m].<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > because the case m = 0 will fail.<br>
>>      >>>      >>      > ...<br>
>>      >>>      >><br>
>>      >>>      >>     Just added this suggestion as an update to GitHub.<br>
>>     Andrés, I<br>
>>      >>>     did it<br>
>>      >>>      >>     with<br>
>>      >>>      >>     your author initials, it's your code!<br>
>>      >>>      >><br>
>>      >>>      >>      > ...<br>
>>      >>>      >>      >>   * The *isPrime *method in Integer makes some<br>
>>      >>>     optimization in<br>
>>      >>>      >>     order to<br>
>>      >>>      >>      >>     run the algorithm in O(sqrt(self)) instead<br>
>>     of the<br>
>>      >>> naive<br>
>>      >>>      >> way in<br>
>>      >>>      >>      >>     O(self). This is very intelligent, but the<br>
>>     constant<br>
>>      >>>     factor<br>
>>      >>>      >>     of this<br>
>>      >>>      >>      >>     method can be still improved significantly.<br>
>>     I share<br>
>>      >>>     with<br>
>>      >>>      >> you my<br>
>>      >>>      >>      >>     implementation of *isPrimeFast *with a small<br>
>>      >>>     explanation.<br>
>>      >>>      >> This<br>
>>      >>>      >>      >>     implementation runs in general more than 3<br>
>>     times<br>
>>      >>> faster<br>
>>      >>>      >> than the<br>
>>      >>>      >>      >>     actual one. I leave you a test that <br>
>> checks the<br>
>>      >>>     correctness<br>
>>      >>>      >>     of it as<br>
>>      >>>      >>      >>     well, and some other tests that check this<br>
>>      >>> complexity I<br>
>>      >>>      >>     mentioned.<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > I see what you did there, but I do not know <br>
>> how to<br>
>>      >>>     reproduce the<br>
>>      >>>      >>     time<br>
>>      >>>      >>      > tests you mention.  I built a sample of integers<br>
>>     between<br>
>>      >>>     1 and<br>
>>      >>>      >>     2^32 (I<br>
>>      >>>      >>      > didn't go up to 2^64 because that would require<br>
>>     O(2^32)<br>
>>      >>>     operations<br>
>>      >>>      >>      > each, and I want that to finish in reasonable<br>
>>     time), and<br>
>>      >>>     I get<br>
>>      >>>      >>      > something like a 2x performance improvement<br>
>>     rather than<br>
>>      >>>     3x.  This<br>
>>      >>>      >>      > seems to make sense because the approach you <br>
>> propose<br>
>>      >>>     halves the \\<br>
>>      >>>      >>      > operations (8 remain out of the 16 the current<br>
>>     code is<br>
>>      >>>     doing, for<br>
>>      >>>      >>      > every batch of 30 potential divisors).<br>
>>      >>>      >>      ><br>
>>      >>>      >>      >     slicer := 1024.<br>
>>      >>>      >>      >     thickness := 255.<br>
>>      >>>      >>      >     maxK := 1 bitShift: 32.<br>
>>      >>>      >>      >     integers := 1 to: maxK by: maxK // slicer<br>
>>      >>>      >>      >         :: inject: OrderedCollection new<br>
>>      >>>      >>      >         into: [:t :x |<br>
>>      >>>      >>      >             t add: x.<br>
>>      >>>      >>      >             thickness timesRepeat: [t add: t<br>
>>     last + 1].<br>
>>      >>>      >>      >             t yourself]<br>
>>      >>>      >>      >         :: asArray.<br>
>>      >>>      >>      >     Time millisecondsToRun:<br>
>>      >>>      >>      >         [1 to: integers size do:<br>
>>      >>>      >>      >             [:x | (integers at: x) isPrime]]<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > Using the above code (which I could not format <br>
>> more<br>
>>      >>>     nicely in this<br>
>>      >>>      >>      > email), I get about 4.8s for isPrime, and about<br>
>>     2.4s for<br>
>>      >>>      >> isPrimeFast.<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > Generally, isPrime shouldn't send<br>
>>     isProbablyPrime because<br>
>>      >>>      >> isPrime is<br>
>>      >>>      >>      > meant to be deterministic, and one shouldn't <br>
>> assume<br>
>>      >>> that the<br>
>>      >>>      >>      > probabilistic algorithm today will happen to<br>
>>     provide the<br>
>>      >>>     correct<br>
>>      >>>      >>      > deterministic answer tomorrow.<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > Why is the (each+31) case first in the trial<br>
>>     division<br>
>>      >>> loop?<br>
>>      >>>      >>      ><br>
>>      >>>      >>      > Andres.<br>
>>      >>>      >><br>
>>      >>>      >>     I'll wait for your consensus on what to do here. <br>
>> Making<br>
>>      >>>     isPrime not<br>
>>      >>>      >>     send<br>
>>      >>>      >>     isProbablyPrime sounds reasonable to me, but folks,<br>
>>     I prefer<br>
>>      >>>     to wait<br>
>>      >>>      >>     for<br>
>>      >>>      >>     your suggestion.<br>
>>      >>>      >><br>
>>      >>>      >>     Thanks,<br>
>>      >>>      >><br>
>>      >>>      >>     --     Juan Vuletich<br>
>>      >>>      >> <a href="http://www.cuis-smalltalk.org" rel="noreferrer" target="_blank">www.cuis-smalltalk.org</a> <<a href="http://www.cuis-smalltalk.org" rel="noreferrer" target="_blank">http://www.cuis-smalltalk.org</a>><br>
>>     <<a href="http://www.cuis-smalltalk.org" rel="noreferrer" target="_blank">http://www.cuis-smalltalk.org</a>><br>
>>      >>>     <<a href="http://www.cuis-smalltalk.org" rel="noreferrer" target="_blank">http://www.cuis-smalltalk.org</a>><br>
>>      >>>      >> <a href="https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev" rel="noreferrer" target="_blank">https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev</a><br>
>>      >>>      >> <a href="https://github.com/jvuletich" rel="noreferrer" target="_blank">https://github.com/jvuletich</a><br>
>>      >>>      >> <a href="https://www.linkedin.com/in/juan-vuletich-75611b3" rel="noreferrer" target="_blank">https://www.linkedin.com/in/juan-vuletich-75611b3</a><br>
>>      >>>      >>     @JuanVuletich<br>
>>      >>>      >><br>
>>      >>>      >>     --     Cuis-dev mailing list<br>
>>      >>>      >> <a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>><br>
>>     <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>>><br>
>>      >>>     <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a><br>
>>     <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>> <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a><br>
>>     <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>>>><br>
>>      >>>      >> <a href="https://lists.cuis.st/mailman/listinfo/cuis-dev" rel="noreferrer" target="_blank">https://lists.cuis.st/mailman/listinfo/cuis-dev</a><br>
>>      >>>      >><br>
>>      >>>      >><br>
>>      >>>     --     Cuis-dev mailing list<br>
>>      >>> <a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>><br>
>>     <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>>><br>
>>      >>> <a href="https://lists.cuis.st/mailman/listinfo/cuis-dev" rel="noreferrer" target="_blank">https://lists.cuis.st/mailman/listinfo/cuis-dev</a><br>
>>      >>><br>
>>      >>><br>
>>      ><br>
>>     --     Cuis-dev mailing list<br>
>>     <a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a> <mailto:<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a>><br>
>>     <a href="https://lists.cuis.st/mailman/listinfo/cuis-dev" rel="noreferrer" target="_blank">https://lists.cuis.st/mailman/listinfo/cuis-dev</a><br>
>><br>
>><br>
-- <br>
Cuis-dev mailing list<br>
<a href="mailto:Cuis-dev@lists.cuis.st" target="_blank">Cuis-dev@lists.cuis.st</a><br>
<a href="https://lists.cuis.st/mailman/listinfo/cuis-dev" rel="noreferrer" target="_blank">https://lists.cuis.st/mailman/listinfo/cuis-dev</a><br>
</blockquote></div>