I have a script that calculates disk space in bytes. I have found a way to convert it to megabytes. I have just run it and i got a this: 1867.603187561035
. Is there
There is an even easier way to round a number to the nearest integer, supposing it is not negative and less than 100000000
:
set NUMBER=1867.603187561035
rem // Enforce fractional part:
set NUMBER=%NUMBER%.
rem // Get integer part:
set /A NROUND=NUMBER+0
rem // Extract fractional part:
set NFRACT=%NUMBER:*.=%0
rem /* Prepend `1` to integer part to avoid trouble with leading `0`
rem (remember that such numbers are interpreted as octal ones);
rem append first fractional digit to integer part, then add `5`: */
set /A NROUND=1%NROUND%%NFRACT:~,1%+5
rem // Strip off first and last digits and return remaining integer:
if %NROUND:~,1% GTR 1 (echo 1%NROUND:~1,-1%) else (echo %NROUND:~1,-1%)
To round a signed number in the range between −100000000
and +100000000
to the nearest integer, use this code snippet:
set NUMBER=1867.603187561035
rem // Enforce fractional part:
set NUMBER=%NUMBER%.
rem // Get integer part:
set /A NROUND=NUMBER+0
rem // Cache sign and remove it temporarily:
if %NROUND% LSS 0 (set /A NROUND=-NROUND & set SIGN=-) else set SIGN=
rem // Extract fractional part:
set NFRACT=%NUMBER:*.=%0
rem /* Prepend `1` to integer part to avoid trouble with leading `0`
rem (remember that such numbers are interpreted as octal ones);
rem append first fractional digit to integer part, then add `5`: */
set /A NROUND=1%NROUND%%NFRACT:~,1%+5
rem // Strip off first and last digits and return remaining integer:
if %NROUND:~,1% GTR 1 (echo %SIGN%1%NROUND:~1,-1%) else (echo %SIGN%%NROUND:~1,-1%)
The above approaches may have problems with numbers with leading zeros (due to the fact that such are interpreted as octal numbers), and the used method of temporarily preceding and appending digits reduces the available numerical range.
However, here is now a script that does not have these restrictions:
findstr
) to check the number format;.5
is only rounded up when the integer part is odd (so 1.5
becomes 2
, and 2.5
becomes 2
too);.5
) by removing the condition if "%NFRACT:~,1%"=="5"
and just keeping the code in the else
clause;So this is the code:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Provide a (signed) fractional number here:
set "NUMBER=%~2"
if defined NUMBER exit /B 1
set "NUMBER=%~1"
if not defined NUMBER set /P NUMBER=""
rem // Check whether or not the provided fractional number is actually such:
cmd /V /C echo(!NUMBER!| > nul findstr /R ^
/C:"^ *[+-][0123456789]* *$" /C:"^ *[+-][0123456789]*\.[0123456789]* *$" ^
/C:"^ *[0123456789]* *$" /C:"^ *[0123456789]*\.[0123456789]* *$" || exit /B
rem // Remove quotation marks, remove leading white-spaces, append dot:
if defined NUMBER set "NUMBER=%NUMBER:"=%
for /F "tokens=* eol= " %%S in (" %NUMBER%.") do set "NUMBER=%%S"
rem // Determine sign:
set "SIGN=" & if "%NUMBER:~,1%"=="-" (
set "NUMBER=%NUMBER:~1%" & set "SIGN=-"
) else if "%NUMBER:~,1%"=="+" (
set "NUMBER=%NUMBER:~1%" & rem set "SIGN=+"
)
rem // Remove leading zeros to avoid interpretation as octal number:
for /F "tokens=* eol=0 delims=0" %%Z in ("%NUMBER%") do set "NUMBER=%%Z"
rem // Split number into integer and fractional parts:
for /F "tokens=1 eol=. delims=." %%I in ("1%NUMBER%") do set "NROUND=%%I"
set "NROUND=%NROUND:~1%" & set "NFRACT=%NUMBER:*.=%0"
for /F "delims=0123456789 eol=0" %%J in ("%NROUND:~1%") do set "NFRACT=0"
rem // Actually round:
if "%NFRACT:~,1%"=="5" (
rem /* Particularly handle the exact fractional portion `.5` in order
rem to round mathematically correct, thus to the nearest even: */
for /F "tokens=* eol=0 delims=0" %%T in ("0%NFRACT:~1%") do (
set "NFRACT=%%T" & set /A "NROUND+=!!(NFRACT+NROUND%%2)"
)
) else (
set "NFRACT=%NFRACT:~,1%" & set /A "NROUND+=NFRACT/5"
)
rem // Correct wrong sign when (2^31 - 1) needed to be rounded up:
if %NROUND% lss 0 set /A "NROUND-=1"
rem // Return resulting rounded number:
if %NROUND% equ 0 (echo %NROUND%) else echo %SIGN%%NROUND%
endlocal
exit /B