0

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?

Cœur
  • 37,241
  • 25
  • 195
  • 267

3 Answers3

2

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?)

npocmaka
  • 55,367
  • 18
  • 148
  • 187
2

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%
rojo
  • 24,000
  • 5
  • 55
  • 101
2

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%
Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108