批处理文件乘以正变量返回负数 [英] Batch file multiply positive variables return a negative number

查看:27
本文介绍了批处理文件乘以正变量返回负数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究批处理多边形面积计算器,但遇到了问题.我需要将 2 个变量相乘,但如果两个正变量很大,有时它会返回一个负数.

这是一个例子:999999*999999 返回 -729379967.

代码如下:

REM Calc 正方形面积:PolySqu类回波多边形面积计算器对于/L %%P In (1,1,57) 做回声.Set/P "InputPolygonCalSqu=输入以厘米为单位的线条长度之一:"Set/A SquArea=InputPolygonCalSqu * InputPolygonCalSqu类回波多边形面积计算器对于/L %%P In (1,1,57) 做回声.Echo 这个正方形的面积是 %SquArea% cm2.暂停转到 :PolygonCal

似乎是命令

Set/A SquArea="InputPolygonCalSqu * InputPolygonCalSqu

计算不正确.

解决方案

正如其他人已经指出的, 本身仅支持 32 位有符号整数运算.

以下代码构成了乘以大于 232 限制的非负数的变通方法 −1 = 2147483647,使用纯 命令(我们称之为 multiply.bat):

@echo offsetlocal EnableExtensions DisableDelayedExpansionrem//在这里定义参数:设置NUM1=%~1"设置NUM2=%~2"设置NUM3=%~3"设置NUM4=%~4"如果定义 NUM1 设置 "NUM1=%NUM1:"=""%如果定义了 NUM2 设置 "NUM2=%NUM2:"=""%如果定义了 NUM3 设置 "NUM3=%NUM3:"=%调用 :VAL_ARGS NUM1 NUM2 NUM4 ||退出/B 1rem//在这里定义常量:设置/A "DIG=4" &设置垫="setlocal EnableDelayedExpansion对于 (1,1,%DIG%) 中的/L %%J 设置 "PAD=!PAD!0"终端本地化设置PAD=%PAD%"rem//确定字符串长度:调用 :STR_LEN LEN1 NUM1调用 :STR_LEN LEN2 NUM2设置/A "LEN1=(LEN1-1)/DIG*DIG"设置/A "LEN2=(LEN2-1)/DIG*DIG"设置/A "LIM=LEN1+LEN2+DIG"对于 (0,%DIG%,%LIM%) 中的/L %%I 设置/A "RES[%%I]=0"rem//执行逐块乘法:setlocal EnableDelayedExpansion对于/L %%J in (0,%DIG%,%LEN2%) 做 (对于/L %%I in (0,%DIG%,%LEN1%) 做 (设置/A "IDX=%%I+%%J"如果 %%I EQU 0(设置AUX1=-%DIG%")否则(set/A "AUX1=%DIG%+%%I" &设置 "AUX1=-!AUX1!,-%%I")if %%J EQU 0 (设置 "AUX2=-%DIG%") else (set/A "AUX2=%DIG%+%%J" &设置 "AUX2=-!AUX2!,-%%J")对于/F "tokens=1,2" %%M in ("!AUX1! !AUX2!") 做 (设置 "AUX1=!NUM1:~%%M!"&设置 "AUX2=!NUM2:~%%N!")呼叫 :NO_LEAD0 AUX1 !AUX1!呼叫 :NO_LEAD0 AUX2 !AUX2!set/A "RES[!IDX!]+=AUX1*AUX2"set/A "NXT=IDX+DIG, DIT=DIG*2"对于/F "tokens=1,2,3" %%M in ("!IDX! !NXT! !DIT!") 做 (设置 "AUX=!RES[%%M]:~-%%O,-%DIG%!"设置/A "RES[%%N]+=AUX"设置 "RES[%%M]=!RES[%%M]:~-%DIG%!"调用 :NO_LEAD0 RES[%%M] !RES[%%M]!)))rem//构建结果产品:设置RES ="&设置AUX="对于/L %%I in (0,%DIG%,%LIM%) 做 (设置/A "RES[%%I]+=AUX"set/A "NXT=%%I+DIG"对于 (!NXT!,%DIG%,!NXT!) 中的/L %%J 做 (设置 "AUX=!RES[%%I]:~-%%J,-%DIG%!")设置 "RES[%%I]=%PAD%!RES[%%I]!"设置 "RES=!RES[%%I]:~-%DIG%!!RES!")终端本地化设置RES=%RES%"调用:NO_LEAD0 RES %RES%rem//返回结果产品:回声(%RES%如果定义了 NUM3 (本地端设置%NUM3%=%RES%") 别的 (本地端)退出/B:NO_LEAD0 rtn_var val_numrem//从数字中删除前导零:for/F "tokens=* delims=0" %%Z in ("%~2") do (设置 "%~1=%%Z" &如果未定义 %~1 设置 "%~1=0")退出/B 0:STR_LEN rtn_length ref_stringrem//检索字符串的长度:setlocal EnableDelayedExpansion设置 "STR=!%~2!"如果没有定义 STR (set/A LEN=0) else (set/A LEN=1)对于 (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) 中的 %%L 做 (如果定义了 STR (设置 "INT=!STR:~%%L!"如果不是 "!INT!"=="" 设置/A LEN+=%%L &设置STR=!INT!"))终端本地化设置%~1=%LEN%"退出/B 0:VAL_ARGS ref_arg1 ref_arg2 ref_arg3rem//检查参数的有效性:如果未定义 %~1 >&2 echo 错误:给出的参数太少!&退出/B 1如果未定义 %~2 >&2 echo 错误:给出的参数太少!&退出/B 1如果定义了 %~3 >&2 echo 错误:给出的参数太多!&退出/B 1(调用 echo "%%%~1%%" | > nul findstr/R/C:"^\"[0-9][0-9]*\" $") ||(>&2 echo ERROR:参数 1 不是纯数字!&退出/B 1)(调用 echo "%%%~2%%" | > nul findstr/R/C:"^\"[0-9][0-9]*\" $") ||(>&2 echo ERROR:参数 2 不是纯数字!&退出/B 1)退出/B 0

使用它提供两个数字相乘作为命令行参数;例如:

multiply.bat 999999 999999

结果产品在控制台返回:

<块引用>

999998000001

如果您提供第三个参数,则将产品分配给具有该名称的变量;例如:

multiply.bat 999999 999999 SquArea

这将变量 SquArea 设置为结果值.后者也仍然在控制台上返回.
要在没有任何额外控制台输出的情况下静默分配变量,请将其重定向到 nul 设备:

multiply.bat 999999 999999 SquArea >空

I've been working on a Batch polygon area calculator and I got a problem. I need to multiply 2 variables, but sometimes it return a negative number if the two positive variables are large.

Here's an example: 999999*999999 returns -729379967.

Code goes below:

REM Calc square area
:PolySqu
Cls
Echo                                        Polygon Area Calculator 
For /L %%P In (1,1,57) Do Echo.
Set /P "InputPolygonCalSqu=Enter one of the line's length in cm :"


Set /A SquArea=InputPolygonCalSqu * InputPolygonCalSqu


Cls
Echo                                        Polygon Area Calculator
For /L %%P In (1,1,57) Do Echo.
Echo The area of this square is %SquArea% cm2.
Pause
Goto :PolygonCal

It seemed the command

Set /A SquArea="InputPolygonCalSqu * InputPolygonCalSqu

doesn't calculate properly.

解决方案

As others already pointed out, a natively supports 32-bit signed integer arithmetics only.

The following code constitutes a work-around for multiplying non-negative numbers greater than the limit of 232 − 1 = 2147483647, using pure commands (let us call it multiply.bat):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define arguments here:
set "NUM1=%~1"
set "NUM2=%~2"
set "NUM3=%~3"
set "NUM4=%~4"
if defined NUM1 set "NUM1=%NUM1:"=""%
if defined NUM2 set "NUM2=%NUM2:"=""%
if defined NUM3 set "NUM3=%NUM3:"=%
call :VAL_ARGS NUM1 NUM2 NUM4 || exit /B 1

rem // Define constants here:
set /A "DIG=4" & set "PAD="
setlocal EnableDelayedExpansion
for /L %%J in (1,1,%DIG%) do set "PAD=!PAD!0"
endlocal & set "PAD=%PAD%"

rem // Determine string lengths:
call :STR_LEN LEN1 NUM1
call :STR_LEN LEN2 NUM2
set /A "LEN1=(LEN1-1)/DIG*DIG"
set /A "LEN2=(LEN2-1)/DIG*DIG"
set /A "LIM=LEN1+LEN2+DIG"
for /L %%I in (0,%DIG%,%LIM%) do set /A "RES[%%I]=0"

rem // Perform block-wise multiplication:
setlocal EnableDelayedExpansion
for /L %%J in (0,%DIG%,%LEN2%) do (
    for /L %%I in (0,%DIG%,%LEN1%) do (
        set /A "IDX=%%I+%%J"
        if %%I EQU 0 (set "AUX1=-%DIG%") else (
            set /A "AUX1=%DIG%+%%I" & set "AUX1=-!AUX1!,-%%I"
        )
        if %%J EQU 0 (set "AUX2=-%DIG%") else (
            set /A "AUX2=%DIG%+%%J" & set "AUX2=-!AUX2!,-%%J"
        )
        for /F "tokens=1,2" %%M in ("!AUX1! !AUX2!") do (
            set "AUX1=!NUM1:~%%M!" & set "AUX2=!NUM2:~%%N!"
        )
        call :NO_LEAD0 AUX1 !AUX1!
        call :NO_LEAD0 AUX2 !AUX2!
        set /A "RES[!IDX!]+=AUX1*AUX2"
        set /A "NXT=IDX+DIG, DIT=DIG*2"
        for /F "tokens=1,2,3" %%M in ("!IDX! !NXT! !DIT!") do (
            set "AUX=!RES[%%M]:~-%%O,-%DIG%!"
            set /A "RES[%%N]+=AUX"
            set "RES[%%M]=!RES[%%M]:~-%DIG%!"
            call :NO_LEAD0 RES[%%M] !RES[%%M]!
        )
    )
)

rem // Build resulting product:
set "RES=" & set "AUX="
for /L %%I in (0,%DIG%,%LIM%) do (
    set /A "RES[%%I]+=AUX"
    set /A "NXT=%%I+DIG"
    for /L %%J in (!NXT!,%DIG%,!NXT!) do (
        set "AUX=!RES[%%I]:~-%%J,-%DIG%!"
    )
    set "RES[%%I]=%PAD%!RES[%%I]!"
    set "RES=!RES[%%I]:~-%DIG%!!RES!"
)
endlocal & set "RES=%RES%"
call :NO_LEAD0 RES %RES%

rem // Return resulting product:
echo(%RES%
if defined NUM3 (
    endlocal
    set "%NUM3%=%RES%"
) else (
    endlocal
)
exit /B


:NO_LEAD0  rtn_var  val_num
rem // Remove leading zeros from a number:
for /F "tokens=* delims=0" %%Z in ("%~2") do (
    set "%~1=%%Z" & if not defined %~1 set "%~1=0"
)
exit /B 0


:STR_LEN  rtn_length  ref_string
rem // Retrieve length of string:
setlocal EnableDelayedExpansion
set "STR=!%~2!"
if not defined STR (set /A LEN=0) else (set /A LEN=1)
for %%L in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
    if defined STR (
        set "INT=!STR:~%%L!"
        if not "!INT!"=="" set /A LEN+=%%L & set "STR=!INT!"
    )
)
endlocal & set "%~1=%LEN%"
exit /B 0


:VAL_ARGS  ref_arg1  ref_arg2  ref_arg3
rem // Check arguments for validity:
if not defined %~1 >&2 echo ERROR: too few arguments given! & exit /B 1
if not defined %~2 >&2 echo ERROR: too few arguments given! & exit /B 1
if defined %~3 >&2 echo ERROR: too many arguments given! & exit /B 1
(call echo "%%%~1%%" | > nul findstr /R /C:"^\"[0-9][0-9]*\" $") || (
    >&2 echo ERROR: argument 1 is not purely numeric! & exit /B 1
)
(call echo "%%%~2%%" | > nul findstr /R /C:"^\"[0-9][0-9]*\" $") || (
    >&2 echo ERROR: argument 2 is not purely numeric! & exit /B 1
)
exit /B 0

To use it provide the two numbers to multiply as command line arguments; for instance:

multiply.bat 999999 999999

The resulting product is returned on the console:

999998000001

If you provide a third argument, the product is assigned to a variable with that name; for example:

multiply.bat 999999 999999 SquArea

This sets variable SquArea to the resulting value. The latter is also still returned on the console.
To silently assign the variable without any additional console output, redirect it to the nul device:

multiply.bat 999999 999999 SquArea > nul

这篇关于批处理文件乘以正变量返回负数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆