Batch rounding a number

后端 未结 5 656
滥情空心
滥情空心 2021-01-25 21:23

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

相关标签:
5条回答
  • 2021-01-25 21:43

    It would be better if you showed the script in question, but yes, rounding can be performed. We just have to do the process manually. Here is a routine that will take in the number and a variable for the result.

    :Round <Input> <Output>
    setlocal
    for /f "tokens=1,2 delims=." %%A in ("%~1") do set "X=%%~A" & set "Y=%%~B0"
    if %Y:~0,1% geq 5 set /a "X+=1"
    endlocal & set "%~2=%X%"
    exit /b 0
    

    Usage:

    @echo off
    setlocal
    call :Round 12345.6789 Out
    echo %Out%
    endlocal
    exit /b 0
    
    0 讨论(0)
  • 2021-01-25 21:47
    @echo off
    set "number_to_round=1867.603187561035"
    
    for /f "tokens=1,2 delims=." %%a  in ("%number_to_round%") do (
      set first_part=%%a
      set second_part=%%b
    )
    
    set second_part=%second_part:~0,1%
    echo %second_part%
    if defined second_part if %second_part% GEQ 5 ( 
    
        set /a rounded=%first_part%+1
    ) else ( 
        set /a rounded=%first_part%
    )
    
    echo %rounded%
    

    OR (with the javascript call you can get more precise results and work with long number (while batch is limited to integers))

    @echo off
    set number_to_round=1867.603187561035
    
    set "beginJS=mshta "javascript:close(new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write(Math.round(%number_to_round%)"
    set "endJS=));""
    
    for /f %%N in (
      '%beginJS%%endJS%'
    ) do set rounded=%%N
    
    echo %rounded%
    
    0 讨论(0)
  • 2021-01-25 21:50

    Here is a native batch/jscript hybrid posted recently that will
    return a MB figure, for a byte figure given as %1 (and not limited to 2GB figures as batch math is)

    It does not round up or round down the partial megabyte after the decimal point, it just removes it.

    @if (@CodeSection == @Batch) @then
    
    @echo off
    set JScall=Cscript //nologo //E:JScript "%~F0"
    for /f "delims=." %%a in ('%JScall% "%~1/1024/1024"') do set "size=%%a"
    echo %size%
    goto :EOF
    
    @end
    WScript.Echo(eval(WScript.Arguments.Unnamed.Item(0)));
    
    0 讨论(0)
  • 2021-01-25 21:53

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

    Update 31-Oct-2020

    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:

    • leading zeros are properly handled;
    • the rounding range lies between -2147483647.5 and +2147483647.5;
    • it is safe against all odd provided strings;
    • it features a check (using findstr) to check the number format;
      this code block may be removed, invalid numbers then result in zero;
    • it rounds in a mathematically correct manner, so it rounds to the nearest even integer, meaning that an exact fractional part .5 is only rounded up when the integer part is odd (so 1.5 becomes 2, and 2.5 becomes 2 too);
      this can easily be changed to the traditional way (to always round up fractional parts of .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
    
    0 讨论(0)
  • 2021-01-25 21:58

    If you just want get the number before the . :

    @echo off
    
    set $value=1867.703187561035
    
    for /f "tokens=1 delims=." %%a in ('echo %$Value%') do set %$number%=%%a
    
    echo %$Number%
    

    And if you really want to test the second part of the number :

    @echo off
    
    setlocal EnableDelayedExpansion
    set $value=1867.703187561035
    
    for /f "tokens=1,2 delims=." %%a in ('echo %$Value%') do (
    set $Number=%%a
    set $Vtest=%%b
    if "!$Vtest:~0,1!" geq "5" set /a $Number+=1
    )
    
    echo !$Number!
    
    0 讨论(0)
提交回复
热议问题