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

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

问题描述

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

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.

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

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

代码如下:

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

似乎是命令

Set /A SquArea="InputPolygonCalSqu * InputPolygonCalSqu

计算不正确.

推荐答案

正如其他人已经指出的那样,本机仅支持32位带符号整数算术.

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

以下代码构成一种变通方法,用于将大于2 32 −的限制的非负数相乘; 1 = 2147483647,使用纯命令(我们称其为multiply.bat):

The following code constitutes a work-around for multiplying non-negative numbers greater than the limit of 232 − 1 = 2147483647, using pure batch-file 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

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

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天全站免登陆