MathGroup Archive 2007

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Re: Fast way of checking for perfect squares?

  • To: mathgroup at smc.vnet.net
  • Subject: [mg83531] Re: [mg83472] Re: Fast way of checking for perfect squares?
  • From: DrMajorBob <drmajorbob at bigfoot.com>
  • Date: Thu, 22 Nov 2007 04:49:36 -0500 (EST)
  • References: <fhu6m6$6pd$1@smc.vnet.net> <32011538.1195659270790.JavaMail.root@m35>
  • Reply-to: drmajorbob at bigfoot.com

My "fasterSquareQ" is still faster than Daniel's function... though I  
can't imagine why!

Clear[intSqrt, intSqrtGuess, intSqrtIterFirst, intSqrtIter]
intSqrtGuess[x_] := intSqrtIterFirst[x, IntegerPart@Sqrt@N@x]
intSqrtIterFirst[x_, y_] := y + Floor[(x - y^2)/(2 y)]
intSqrt[x_?IntegerQ] := Which[
   x < 4, 1,
   x < 9, 2,
   x < 16, 3,
   x < 25, 4,
   True, FixedPoint[intSqrtIter[x], intSqrtGuess[x]]]
intSqrtIter[x_] = # + Floor[Min[0, x - #^2]/(2 #)] &;

slowSquareQ = IntegerQ@Sqrt@# &;
squareQ = intSqrt[#]^2 == # &;
fasterSquareQ = intSqrtGuess[#]^2 == # &;
lichtblau[ee_] :=
  Module[{prec = Log[10., ee], sqrt},
   sqrt = Sqrt[N[ee, prec + $MachinePrecision]];
   sqrt == Round[sqrt]]

data = Table[RandomInteger[10^10], {5*10^5}];
Timing[s1 = Select[data, slowSquareQ];]
Timing[s2 = Select[data, squareQ];]
Timing[s3 = Select[data, fasterSquareQ];]
Timing[s4 = Select[data, lichtblau];]
s1 == s2 == s3 == s4

{48.266, Null}

{16.5, Null}

{7.281, Null}

{15.937, Null}

True

Bobby

On Wed, 21 Nov 2007 01:52:27 -0600, Jean-Marc Gulliet  
<jeanmarc.gulliet at gmail.com> wrote:

> michael.p.croucher at googlemail.com wrote:
>
>> Lets say I have a lot of large integers and I want to check to see
>> which ones are perfect squares - eg
>>
>> data = Table[RandomInteger[10000000000], {100000}];
>>
>> I create a function that takes the square root of each one and checks
>> to see if the result is an integer
>>
>> slowSquareQ := IntegerQ[Sqrt[#1]] &
>>
>> This works fine:
>>
>> Select[data, slowSquareQ] // Timing
>>
>> {11.39, {6292614276, 2077627561}}
>>
>> but I am wondering if I can make it faster as my actual application
>> has a LOT more numbers to test than this.  This was a question posed a
>> few years ago in this very newsgroup and the suggestion was to use a
>> test of the form MoebiusMu[#]==0.
>>
>> Well the MoeboisMu function is new to me so I experimented a little
>> and sure enough when you apply the MoebiusMu function to a perfect
>> square number the result is zero.
>>
>> MoebiusMu[4] = 0
>>
>> The problem is that lots of other numbers have this property as well -
>> eg
>>
>> MoebiusMu[8] =0
>>
>> despite this minor problem I determined that applying the test
>> MoebiusMu[#]==0 on a list of integers is fater than my slowSquareQ:
>>
>> mobSquareQ := If[MoebiusMu[#1] == 0, True, False] &
>> Select[data, mobSquareQ]; // Timing
>>
>> gives a result of 8.156 seconds compared to 11.39 for slowSquareQ.  On
>> my test data I had around 39,000 integers that passed this test which
>> is a shame but at least I have eliminated the other 61,000 or so.  So
>> I thought that maybe I can use the faster MoebiusMu test as a filter:
>>
>> SquareQ := If[MoebiusMu[#1] == 0, slowSquareQ[#1], False] &
>> Select[data, SquareQ] // Timing
>> {11.312, {6292614276, 2077627561}}
>>
>> So after all that I have saved just a few tenths of a second.  Not
>> very impressive.  Can anyone out there do any better?
>> Please forgive me if I have made any stupid mistakes but I have a cold
>> at the moment.
>
> Daniel Lichtblau's reply to the thread "Changing Pure Function in
> Module" (Jul 14 2001) contains the code of a fast function that tests
> for perfect squareness (see Daniel Lichtblau's squaretest2 function
> below). You should read Daniel's reply for detailed explanations,
> additional code, and benchmarking, at
>
> http://groups.google.com/group/comp.soft-sys.math.mathematica/msg/5b31817c4a697041
>
>
> On my system, squaretest2 is about twice faster than slowSquareQ.
>
> In[8]:= squaretest2[ee_] :=
>   Module[{prec = Log[10., ee], sqrt},
>    sqrt = Sqrt[N[ee, prec + $MachinePrecision]];
>    sqrt == Round[sqrt]]
>
> data = Table[RandomInteger[10000000000], {100000}];
>
> In[10]:= Select[data, squaretest2] // Timing
>
> Out[10]= {6.203, {}}
>
> In[11]:= mobSquareQ := If[MoebiusMu[#1] == 0, True, False] &
> Select[data, mobSquareQ]; // Timing
>
> Out[12]= {8.578, Null}
>
> In[13]:= slowSquareQ := IntegerQ[Sqrt[#1]] &
> Select[data, slowSquareQ] // Timing
>
> Out[14]= {12.235, {}}
>
> HTH,



-- 

DrMajorBob at bigfoot.com


  • Prev by Date: Re: Scalars Instead of Lists with One Element
  • Next by Date: Re: Re: SeriesCoefficient: needs work!
  • Previous by thread: Re: Fast way of checking for perfect squares?
  • Next by thread: Re: Fast way of checking for perfect squares?