2
$\begingroup$

This is a basic question - I'm just unfamiliar with Mathematica. For a given $n$, I'd like to find integral $b$ and $k$ such that $bn + k^2$ is a perfect square. I know that $k$ and $b$ are less than $50$. Here's what I've tried:

perfectSquare[n_] := Sqrt[n] == Round[Sqrt[n]];
KandB[n_] := {k, b}
for[k = 0, k < 50, k++,
  for[b = 0, b < 50, b++,
   perfectSquare[b*n + k^2]]];
KandB[n]

This returns $\{1,1\}$ regardless of what $n$ is. I assume there's some issue with the syntax I used when defining the KandB function. Can anyone help?

$\endgroup$
1
  • 1
    $\begingroup$ Why not use FindInstance instead, e.g. for n=21 do FindInstance[ 21 b + k^2 == m^2 && k < 50 && b < 50, {b, k, m}, PositiveIntegers] $\endgroup$
    – Carl Woll
    Apr 6, 2023 at 16:11

2 Answers 2

3
$\begingroup$

This is certainly a good start, and your question is quite valid. It seems to me like you have a more Python-esque/C++ approach to coding, which is by all means valid in MMA. There are a few things that you need to know:


1. Built-in functions are always capitalised

This is true for the For function as well. I have taken the liberty to amend this in your post, so now your For loop should work to do what you programmed it to do.

2. Your defined functions of perfectSquare and KandB are partially incomplete

Your perfectSquare function returns a binary response as well from how it has been constructed. Ideally you want to program it so that it returns the values and use the function $b n + n k^2$ as a criterion for selection.

@lericr's solution very elegantly demonstrates that, and it is very much in line with what most experienced users would do.

As for KandB it is a function that does not depend on its defined variables. This is akin to saying f(x) = y+z. You can appreciate that no matter what value of x you introduce, your function will always return the variable independent components of y and z.


The "boring" For loop way

perfectSquare[n_] := Sqrt[n] == Round[Sqrt[n]];

n=1; (* lets keep this constant for now *)
myList = {}; (*make an empty list*)
For[k = 0, k < 50, k++,
 For[b = 0, b < 50, b++,
  If[perfectSquare[b*n + k^2], AppendTo[myList, {k, b}]]]] (* populate the list if the selection criterion is met*)

myList (* check what is inside*)

enter image description here


Using Tables

For loops are good, but try to avoid them. There are more optimised means to achieve the same result.

perfectSquare[n_] := Sqrt[n] == Round[Sqrt[n]];

Clear[KandB]
KandB[n_Integer] := 
 Flatten[Table[If[perfectSquare[b*n + k^2], {k, b}, Nothing], {k, 0, 50}, {b, 0, 50}], 1]

KandB[1.1] (* checking that the function returns nothing for a Real value*)
KandB[1] (* checking that that the integer value produces the desired result*)

The "elegant" way ;)

Both @lericr and @Carl Woll gave beautiful answers. The former does essentially exactly what the Table method above achieves however Tuple generation and the Select function are highly optimised within mathematica and will absolutely outperform Table any day but most typically not in any way that matters (we are talking about milliseconds here!). The only argument for Tables is readability for a less-experienced coder.

FindInstance is a very powerful function but it is more limited in my opinion as it needs to be tweaked to work as you want it to.

$\endgroup$
3
  • $\begingroup$ Thank you so much, this answer is more comprehensive than anything I expected! I really appreciate you taking the time to share your knowledge $\endgroup$ Apr 6, 2023 at 18:59
  • $\begingroup$ One more question: my $n$ is a huge number, and the "for loop" way ran much more quickly than the "FindInstance" way. What part of the FindInstance implementation makes for the difference in runtimes? $\endgroup$ Apr 6, 2023 at 19:20
  • $\begingroup$ Although FindInstance is a powerful function, I do not think it is suitable for this purpose. I would go either with the Table method or the one suggested by lericr. Try both and see which one suits you better. Personally, I would have used a function that uses Select, much like lericr. Having said that: By using Table (without the Flatten) what is revealed very clearly is that for larger values of $n$, you have to significantly increase the scanning range of $k$ and $b$. $\endgroup$
    – alex
    Apr 6, 2023 at 19:33
4
$\begingroup$

I'm not sure how you want to handle n exactly, but with this range of integers a brute force method works fine:

MyPerfectSquare[n_Integer][{k_Integer, b_Integer}] := IntegerQ[Sqrt[b*n + k^2]];
Select[Tuples[Range@50, 2], MyPerfectSquare[1]]

{{1, 3}, {1, 8}, {1, 15}, {1, 24}, <<more results here>>, {22, 45}, {23, 47}, {24, 49}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.