批处理中的浮点数除法

18

我需要在DOS批处理中进行浮点除法。

我找不到实现方法。类似于这样的:

SET /A Res=10/3

返回一个整数。

这可行吗?


你到底为什么需要这样做?你考虑过VBScript或其他脚本引擎吗? - Jonas Elfström
我一直在开发一个批量大数库,但是它仍然非常不完整。 - Joey
如果您仍然有兴趣使用纯批处理完成此操作,请参考以下链接:https://www.dostips.com/forum/viewtopic.php?t=3854 - Squashman
8个回答

10

我知道这是一个非常古老的话题,但我在之前的所有回答中都找不到一个简单的批处理方法,所以我在这里发布了一个非常简单易用的纯批处理解决方案。

在批处理中使用定点算术执行操作很简单。 "定点"意味着您必须预先设置一定数量的小数位,并在整个操作过程中保持不变。两个定点数之间的加法和减法操作直接执行。乘法和除法操作需要一个辅助变量,我们可以称之为“one”,其值为带有正确小数位数(即“0”位数字)的1。在乘法后,将乘积除以“one”;在除法之前,将被除数乘以“one”。以下是代码:

@echo off
setlocal EnableDelayedExpansion

set decimals=2

set /A one=1, decimalsP1=decimals+1
for /L %%i in (1,1,%decimals%) do set "one=!one!0"

:getNumber
set /P "numA=Enter a number with %decimals% decimals: "
if "!numA:~-%decimalsP1%,1!" equ "." goto numOK
echo The number must have a point and %decimals% decimals
goto getNumber

:numOK
set numB=2.54

set "fpA=%numA:.=%"
set "fpB=%numB:.=%"

set /A add=fpA+fpB, sub=fpA-fpB, mul=fpA*fpB/one, div=fpA*one/fpB

echo %numA% + %numB% = !add:~0,-%decimals%!.!add:~-%decimals%!
echo %numA% - %numB% = !sub:~0,-%decimals%!.!sub:~-%decimals%!
echo %numA% * %numB% = !mul:~0,-%decimals%!.!mul:~-%decimals%!
echo %numA% / %numB% = !div:~0,-%decimals%!.!div:~-%decimals%!
例如:
Enter a number with 2 decimals: 3.76
3.76 + 2.54 = 6.30
3.76 - 2.54 = 1.22
3.76 * 2.54 = 9.55
3.76 / 2.54 = 1.48

非常好!我不知道为什么这不是被接受的答案,因为它非常简单;将整数乘以10000以获得4个更多的小数,依此类推。 - Gustavo6046
这段代码的问题在于,当您将numA输入为0.17时,结果会出错,因为前导零会使其被解释为八进制数。 - George Robinson
代码很聪明,但容易出错。例如 set decimals=3set numB=1000.000 然后输入 17.000。代码返回的是 "17.000 / 1000.000 = .17",但正确答案应为 .017。 - hunterhogan
代码很聪明,但容易出错。例如 set decimals=3set numB=1000.000,然后输入 17.000。代码返回的结果是 "17.000 / 1000.000 = .17",但正确答案应该是 .017。 - undefined

6

批处理文件本身不支持浮点数算术。然而,这篇文章提供了一种解决方法,使用外部脚本文件进行计算。脚本文件应该使用某种eval函数来评估传递的表达式并返回结果。下面是一个示例VBScript文件(eval.vbs):

WScript.Echo Eval(WScript.Arguments(0))

你可以从批处理文件中调用此外部脚本,指定要求值的表达式并获得结果。例如:
@echo off
for /f %%n in ('cscript //nologo eval.vbs "10/3"') do (
  set res=%%n
)
echo %res%

当然,你将会得到一个字符串作为结果,但总比没有好,你可以把获得的结果作为另一个表达式的一部分传递给eval脚本。

你至少不能将结果传递给另一个 eval 脚本。数字的格式是针对您当前的语言环境进行设置的。在我的情况下,这意味着逗号“,”被用作小数点。如果我将结果再次放入脚本中,这将导致语法错误。 - Joey

3

尝试一下这个

SETLOCAL EnableExtensions EnableDelayedExpansion
call :calc_ 1 (99-(100*5/100^)^)
echo !calc_v!
goto :EOF
:calc_
set scale_=1
set calc_v=
for /l %%i in (1,1,%1) do set /a scale_*=10
set /a "calc_v=!scale_!*%2"
set /a calc_v1=!calc_v!/!scale_!
set /a calc_v2=!calc_v!-!calc_v1!*!scale_!
set calc_v=!calc_v1!.!calc_v2!
goto :EOF

只需要更改

调用:calc_decimalpoint方程

例如

decimalpoint为1

equation为(99-(100*5/100^)^) ;如果使用(),请确保在)之前插入^,如^)

答案是94.0

如果decimalpoint为2

并且equation为22/7 ;π pi

答案是3.14


3
根据这个参考资料,DOS批处理语言中没有浮点类型:
尽管变量在DOS批处理编程语言中确实存在,但它们非常有限。没有整数、指针或浮点变量类型,只有字符串。
我认为如果不显式地实现自己的除法方案来计算余数,你想做的事情是不可能的。

3
虽然它们仅仅是字符串,但使用 set /a 命令可以进行带符号的32位整数算术运算。 - Joey

2
我最近发现了这个用于计算Pi的批处理文件。 其中有一个名为DivideByInteger的标签可能对你有用:愚蠢的编码技巧:一批Pi 它使用一组MaxQuadIndex变量,每个变量包含一个四位数(四元组),以存储整个结果。该代码允许除以介于1和10000之间的整数。
:DivideByInteger
    if defined PiDebug echo.DivideByInteger %1 %2
    set /a DBI_Carry = 0
    for /L %%i in (!MaxQuadIndex!, -1, 0) do (
        set /a DBI_Digit = DBI_Carry*10000 + %1_%%i
        set /a DBI_Carry = DBI_Digit %% %2
        set /a %1_%%i = DBI_Digit / %2
    )
    goto :EOF

一个名为Print的标签也可用...

1

我写了一个专门用于除法的批处理文件。它会接收你输入的第一个数字,然后将其除以第二个数字,并按照你指定的小数位数显示结果。

Echo off
cls
if NOT "%3" == "" (
set n1=%1
set n2=%2
set max=%3
goto :begin
)

set counter=2
set n1=1
set n2=1
set ans=
:start
Echo.
Echo. 1 / 2
Echo.
Set /p N1= 1?
set /p N2= 2?
Set /p Max= Out how many Decimal Points?
:begin
set /a TmpAns=%N1%/%N2%
set ans=%TmpAns%.
:: Echo.%ans%.>Answer.txt
<nul set /p "=%Tmpans%."
set /a TmpSub=%N2%*%TmpAns%
set /a N1=%N1%-%TmpSub%
set N1=%N1%0
If NOT "%n1%" == "00" (
if %n1% LSS %N2% (
set N1=%N1%0
set ans=%ans%0
)
) else (
Goto :Finished
)
set count=0

:loop
If "%count%" == "%max%" (
Goto :Finished
)

set /a TmpAns=%N1%/%N2%
set ans=%ans%%TmpAns%
<nul set /p "=%Tmpans%"
set /a TmpSub=%N2%*%TmpAns%
set /a N1=%N1%-%TmpSub%
set N1=%N1%0
If NOT "%n1%" == "00" (
if %n1% LSS %N2% (
set N1=%N1%0
set ans=%ans%0
)
) else (
Goto :Finished
)
set /a count=%count%+1
goto :loop

:finished
cls
Echo.
Echo.
Echo.The Number
Echo.%ans%
Echo.
Echo.
set n1=1
set n2=1
pause
goto :eof

:eof

答案存储在变量%Ans%中。也可以使用参数调用(“Divide.bat 50 27 5”将给出50/27的结果,保留5位小数)。


1

现在几乎所有的机器都有PowerShell,因此我会让PowerShell来计算并将结果返回给批处理程序。

示例:

set divident=10
set divisor=3
for /f "delims=" %%a in ('powershell -Command %divident%/%divisor%') do set result=%%a
@echo %result%

解释:

输入变量: 使用set变量来定义被除数和除数。

调用powershell并将结果赋值给批处理变量: for /f "delims=" %%a in ('powershell -Command ...) do set result=%%a (你也可以在这里查看: 如何将单个PowerShell输出字符串放入cmd变量中?)

请注意上述代码仅适用于整数输入变量。 为支持浮点数输入变量,我们需要将变量作为带引号的字符串发送(“%variable%”),并在PowerShell中将字符串转换回Double,否则批处理将解释逗号作为分隔符,而PowerShell无法解释数字。

示例:

set divident=10,5
set divisor=3,4
for /f "delims=" %%a in ('powershell -Command [convert]::ToDouble^(\"%divident%\"^)
                                        /[convert]::ToDouble^(\"%divisor%\"^)') do set result=%%a
@echo %result%

说明:

在PowerShell中,您可以像这样操作:[convert]::ToDouble("10,5")/[convert]::ToDouble("3,5")。然而,在批处理中,我们需要使用反斜杠转义引号,并且还需要在引号部分前后添加"^"符号:[convert]::ToDouble^("%divident%"^)/[convert]::ToDouble^("%divisor%"^)


0
如果您在Windows命令行中运行(而不是DOS),您可以使用VBScript来计算包括浮点数在内的复杂表达式。
我编写了一个小助手库,您可以调用它来完成这个任务。 GitHub上的EvalBat Library

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接