tinylisp, 125 117 109 bytes
(d X(q((N I)(i(l N 1)N(X(s N I)(a I 2
(d S(q((I N)(i(a(X I 1)(X(s N I)1))(i(l N I)0(S(a I 1)N))1
(q((N)(S 0 N
The last line is an anonymous function that takes a number and returns 1 if it is the sum of two squares, 0 otherwise. Try it online!
Ungolfed/explanation
Look, ma, no library!
First, we define a helper function X
that takes a number N
and determines if it is (not) a square. A perfect square is the sum of consecutive odd numbers; therefore, subtracting the sum of the first several odd numbers from N
(for an appropriate value of "several") will result in 0 if N
is square. Thus, we recurse over increasingly large odd numbers (which we track as I
) and subtract each one from N
until N
equals 0 (in which case N
is square) or N
is less than 0 (in which case N
is not square):
(def not-square? ; Define not-square?
(lambda (N I) ; as a function of two arguments:
(if (less? N 1) ; If N is less than 1,
N ; return N (0 if square, negative if not square)
(not-square? ; Else, recurse with these arguments:
(sub2 N I) ; New N is previous N minus current odd number
(add2 I 2))))) ; New I is the next odd number
Next, we'll define a function S
that determines whether a number N
is the sum of two squares. Our algorithm here is to recurse over integers I
starting at 0: if I
is not square, or N
minus I
is not square, try the next I
until N
is less than I
, at which point N
cannot be the sum of two squares. On the other hand, if I
and N
minus I
are both square, then N
is the sum of two squares.
(def sum-squares? ; Define sum-squares?
(lambda (I N) ; as a function of two arguments:
(if ; If
(add2 ; the sum of
(not-square? ; 0 if
(sub2 N I) ; N minus I
1) ; is square, < 0 otherwise
; and
(not-square? I 1)) ; 0 if I is square, < 0 otherwise
; is truthy (nonzero), then:
(if (less? N I) ; If N is less than I
0 ; then return 0
(sum-squares? ; Else, recurse with these arguments:
(add2 I 1) ; New I is the next integer
N)) ; Same N
1 ; Else (I and N minus I are both square), return 1
Finally, our submission is an anonymous function that takes N
only and passes it to sum-squares?
with a starting I
of 0:
(lambda (N)
(sum-squares? 0 N))