18

I need to do a floating-point division in a dos batch.

I didn't find a way to do it. Something like this :

SET /A Res=10/3

returns a integer number.

Is it possible to do it ?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Jérôme
  • 26,567
  • 29
  • 98
  • 120

8 Answers8

10

I know this is a very old topic, but I can't found a simple Batch method in all previous answers, so I post here a pure Batch solution that is very simple to use.

Perform operations using fixed point arithmetic in Batch is simple. "Fixed point" means that you must set a number of decimals in advance and keep it throughout the operations. Add and subtract operations between two Fixed Point numbers are performed directly. Multiply and division operations requires an auxiliary variable, that we can call "one", with the value of 1 with the right number of decimals (as "0" digits). After multiply, divide the product by "one"; before division, multiply the dividend by "one". Here it is:

@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%!

For example:

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
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Very good! I don't know how this isn't the accepted answer as it is very simple; multiply an integer by 10000 to get 4 more decimals, and so on. – wallabra Oct 16 '16 at 18:03
  • The problem with this code is when you enter `0.17` for `numA` then the result will be wrong because the leading zero will make it interpret as an octal number, – George Robinson Aug 09 '20 at 00:44
  • The code is clever, but it is prone to errors. For example `set decimals=3`, `set numB=1000.000` and enter 17.000. The code returns "17.000 / 1000.000 = .17" but the correct answer is .017. – hunterhogan Jun 05 '23 at 06:16
6

Batch files as such do not support the floating point arithmetic. However, this article suggests a workaround that uses an external script file to do calculations. The script file should use some sort of eval function to evaluate the expression passed as an argument and return the result. Here's a sample VBScript file (eval.vbs) that does this:

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

You can call this external script from your batch file, specify the expression to be evaluated and get the result back. For example:

@echo off
for /f %%n in ('cscript //nologo eval.vbs "10/3"') do (
  set res=%%n
)
echo %res%

Of course, you'll get the result as a string, but it's better than nothing anyway, and you can pass the obtained result to the eval script as part of another expression.

Helen
  • 87,344
  • 17
  • 243
  • 314
  • You can't pass the result to another eval script – not in the general case at least. The numbers are formatted for your current locale. In my case this means that the comma `,` is used as decimal point. This leads to a syntax error if I were to put the result into the script again. – Joey Jun 25 '10 at 06:49
3

According to this reference, there is no floating point type in DOS batch language:

Although variables do exist in the DOS batch programming language, they are extremely limited. There are no integer, pointer or floating point variable types, only strings.

I think what you are trying to do will be impossible without implementing your own division scheme to calculate the remainder explicitly.

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
  • 3
    Even though they are only strings you can do signed 32-bit integer arithmetic with `set /a`. – Joey Oct 01 '09 at 16:30
2

try this

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

just change

call :calc_ decimalpoint equataion

in the example

decimalpoint is 1

equataion is (99-(100*5/100^)^) ;make sure if you use () that you insert ^ before ) as in ^)

the answer is 94.0

if decimalpoint is 2

and equataion is 22/7 ;π pi

the answer is 3.14

Community
  • 1
  • 1
2

I recently came across this batch file to compute an approximation of Pi. There is a DivideByInteger label that might be useful to you: Stupid-Coding-Tricks-A-Batch-of-Pi

It uses a set of MaxQuadIndex variables, each containing a four-digit number (quadruple), in order to store the entire result. The code allows division by an integer between 1 and 10000, inclusive.

: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

A Print label is also available…

mousio
  • 10,079
  • 4
  • 34
  • 43
1

I wrote a pure batch file specifically to do division. It takes the first number you input, and then divides it by the second one, and displays the result with as many decimal points as you specify.

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

The answer put into the variable %Ans%. It can also be called with parameters. ("Divide.bat 50 27 5" would give you 50/27 out 5 decimal points.)

1

Since nowadays PowerShell is present on almost all machines, I would let PowerShell do the math and return the result to the batch.

Example:

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

Explanation:

Input variables: Use set variables to define divident and divisor.

Calling powershell and assign result to a batch variable: for /f "delims=" %%a in ('powershell -Command ...) do set result=%%a (you may also check here: How to put a single PowerShell output string into a cmd variable?)

Note the above code will only work with integer input variables. To support floating point input variables, we need to send the variables as strings inside quotations ("%variable%") and convert the strings within PowerShell back to Double, otherwise batch would interpret the commas as delimiters and PowerShell could not interpret the numbers.

Example:

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%

Explanation:

Note in PowerShell you would do this like [convert]::ToDouble("10,5")/[convert]::ToDouble("3,5"). However in batch we need to escape the quotes using backslash, and we also need to add a "^" sign before and after the quoted parts: [convert]::ToDouble^("%divident%"^)/[convert]::ToDouble^("%divisor%"^)

0

If you're running in a command shell on Windows (rather than DOS), you can use VBScript to evaluate complex expressions including floating point math for you.

I have written a small helper library you can call to do this.

EvalBat Library on GitHub

Adisak
  • 6,708
  • 38
  • 46