I'm trying to write a program in Batch that puts numbers into simplified radical form. Is there a way to check if a number is a perfect square?
-
Stop writing batches, there are great alternatives – Marged Mar 02 '16 at 20:03
-
1Translation: "I don't know how to solve this in batch, so you need to learn a different language." -- [Marged](http://stackoverflow.com/users/1354537/marged) – rojo Mar 03 '16 at 15:36
-
@rojo: Excellent comment! **`+oo`** – Aacini Mar 04 '16 at 16:32
3 Answers
the easiest way is with with embedded jscript code.Here's example with a subroutine that accepts a number prints yes or no depending on if the number is square or not and sets errorlevel on 1 if it is:
@echo off
call :isSquare 81
call :isSquare 7
call :isSquare 9
if errorlevel 1 (
echo 9 is a square number
)
exit /b %errorlevel%
:isSquare
setlocal
set /a number=%~1
:: Define simple macros to support JavaScript within batch
set "beginJS=mshta "javascript:code(close(new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write("
set "endJS=)));""
:: FOR /F does not need pipe
for /f %%N in (
'%beginJS% Math.sqrt(%number%) %endJS%'
) do set sqrt=%%N
if "%sqrt%" equ "%sqrt:.=%" (
echo Yep!
endlocal & exit /b 1
) else (
echo Nope!
endlocal & exit /b 0
)
endlocal
Now I'm thinking about pure batch solution (may be checking a list with all 34bit square numbers?)

- 55,367
- 18
- 148
- 187
The easiest way is to use a PowerShell command.
@echo off
setlocal
call :isSquare 25 && (
echo The square root is an integer.
) || (
echo The square root is a float.
)
goto :EOF
:isSquare <num>
for /f "tokens=2 delims=." %%I in ('powershell "[math]::Sqrt(%1)"') do exit /b 1
exit /b 0
It's slower than npocmaka's JScript macro though.
Here's a pure batch solution based on an algorithm found on Wikipedia. (See the section labeled "Binary numeral system (base 2)" for details.) The :sqrt
function sets errorlevel 0 if the number is a perfect square, non-zero if not; and sets a variable to the result. It's quite fast.
@echo off
setlocal
set num=2147395600
call :sqrt %num% foo && (
call echo The square root of %num% is %%foo%%
) || (
echo %num% is not a perfect square
)
goto :EOF
:sqrt <num> <return_var>
setlocal enabledelayedexpansion
set /a "res = 0, bit = 1 << 30, num = %~1"
:sqrt_loop1
if %bit% gtr %num% (
set /a "bit >>= 2"
goto :sqrt_loop1
)
:sqrt_loop2
if %bit% neq 0 (
set /a resbit = res + bit
if %num% geq !resbit! (
set /a "num -= resbit, res >>= 1, res += bit"
) else set /a "res >>= 1"
set /a "bit >>= 2"
goto sqrt_loop2
)
set /a "ret = %~1 - (res * res)"
endlocal & set "%~2=%res%" & exit /b %ret%

- 24,000
- 5
- 55
- 101
The pure Batch file solution below, that appears at this question, also get the closest perfect square if the given number is not one.
@echo off
setlocal
cls
set /P "N=Enter a number: "
set /A "x=N/(11*1024)+40, x=(N/x+x)>>1, x=(N/x+x)>>1, x=(N/x+x)>>1, x=(N/x+x)>>1, x=(N/x+x)>>1, x+=(N-x*x)>>31, M=x*x"
if %N% equ %M% (
echo %N% is perfect square
goto :EOF
)
set /A "I=(x+1)*(x+1), ID=I-N, MD=N-M"
if %ID% lss %MD% set M=%I%
echo The closest perfect square is %M%