Update running unsigned long long sum in bat file - batch-file

Is there a simple way to sum two numbers potentially >= 2*31 in a .BAT file?
I have a running sum, and argument %1 that is the name of an existing file.
set sum=4123456789
set fsize=%~z1
I'd like to add fsize to sum. Unfortunately fsize (and sum) can be as tiny as zero or 10's of gigabytes (%~z1 accurately reports >= 2*31 file sizes).
I know a program could do it, and I'll go that route if necessary, but I'd prefer to do it with a few added lines of .BAT logic.

I think the easiest way is to split the summands into two parts – integer and fractional Gigas (multiples of 1000000000), add the respective parts individually, then recombine them. See the following example script, which contains a lot of explanatory remarks:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Initialise variables:
set /A "GIGASUM=0, FRACSUM=0"
:LOOP
rem // Get command line argument:
shift
set "NUM=%~0"
if not defined NUM goto :NEXT
rem // Check number for validity:
(for /F "delims=0123456789" %%N in ("%NUM%") do rem/) && (
echo ERROR: non-numeric characters encountered!
exit /B 1
)
rem // Split number into two parts, integer and fractional Gigas:
set "NUM=000000000%NUM%"
set "GIGA=%NUM:~,-9%" & set "FRAC=%NUM:~-9%"
rem // Remove leading zeros from integer Gigas:
for /F "tokens=* delims=0" %%N in ("%GIGA%") do set "GIGA=%%N"
rem // Sum up fractional Gigas and determine carry:
set /A "FRACSUM+=(1%FRAC%-1000000000)"
set "CARRY=%FRACSUM:~,-9%" & set "FRACSUM=000000000%FRACSUM%"
set "FRACSUM=%FRACSUM:~-9%"
rem // Sum up integer Gigas and regard carry:
set /A "GIGASUM+=GIGA+CARRY"
rem // Loop back to next summand:
goto :LOOP
:NEXT
rem // Remove leading zeros:
for /F "tokens=* delims=0" %%N in ("%GIGASUM%%FRACSUM%") do set "SUM=%%N"
if not defined SUM set "SUM=0"
rem // Return resulting sum:
echo %SUM%
endlocal
exit /B
The greatest possible sum amounts to 231 * 109 – 1 = 2147483647999999999, an overflow is not detected.

The required logic is not so complicated. Here it is one version:
#echo off
setlocal
:loop
set /p "pair=Enter two numbers separated by plus sign: "
if errorlevel 1 goto :EOF
for /F "tokens=1,2 delims=+" %%a in ("%pair%") do set "num1=%%a" & set "num2=%%b"
set "sum="
set "carry=0"
:nextDigit
set /A sum1=%num1:~-1%+%num2:~-1%+carry
set "sum=%sum1:~-1%%sum%"
set /A carry=sum1/10
set "num1=%num1:~0,-1%"
if not defined num1 set "num1=0"
set "num2=%num2:~0,-1%"
if not defined num2 set "num2=0"
if "%carry%%num1%%num2%" neq "000" goto nextDigit
echo The sum is: %sum%
goto loop

Related

Command prompt script to subtract variables

I know there are many arithmetic questions on here, but I have not found the specific answer to my question. I have a file with two values in it, the first always higher than the second. Today, the txt file has:
21.04
20.94
What I am trying to do is, via a batch file, subtract the second number from the first, and then insert than on a new line. Any assistance is appreciated.
Just incorporate powershell into the batch file.
to test from cmd:
#for /f %i in ('powershell 21.04 - 20.94') do #echo %i
So you can build a very basic calculator rather easily.
set /p "first=Enter first number: "
set /p "second=Enter Second Number: "
set /p "function=Select Function(+-/): "
powershell %first% %function% %second%
And offcourse you can use a for loop to assign the value to a variable should you want to use it elsewhere in your batch file.
#echo off
set /p "first=Enter first number: "
set /p "second=Enter Second Number: "
set /p "function=Select Function(+-/): "
for /f %%i in ('powershell %first% %function% %second%') do set "result=%%i"
echo %result%
in a batch-file you double the % in meta variables to %%i
Assuming file is called math.txt
#echo off
setlocal enabledelayedexpansion
set cnt=1
for /f "usebackq" %%i in ("d:\math.txt") do (
set var!cnt!=%%i
set /a cnt+=1
)
(powershell %var1% - %var2%)>output.txt
pause
This method works with numbers up to 9 total digits (and any number of decimals) as long as the input numbers have the same number of decimals:
#echo off
setlocal EnableDelayedExpansion
rem Read two numbers
( set /P "num1=" & set /P "num2=" ) < test.txt
rem Adjust *two* numbers for given decimals
set "decimals=2"
for %%i in (1 2) do (
set "num%%i=!num%%i:.=!"
for /L %%d in (1,1,%decimals%) do if "!num%%i:~0,1!" equ "0" set "num%%i=!num%%i:~1!"
)
rem Subtract second number from the first
set /A "result=num1 - num2"
rem Adjust result for given number of decimals
for /L %%d in (1,1,%decimals%) do if "!result:~%decimals%!" equ "" set "result=0!result!"
rem Output result with decimals
echo !result:~0,-%decimals%!.!result:~-%decimals%!
I think this works for reasonably sized numbers:
#echo off
rem read values from file specified as command line parameter
(
set /p value1=
set /p value2=
)<%1
rem split first value into whole and fractional parts
for /f "tokens=1,2 delims=." %%a in ("%value1%") do (
set beforedot1=%%a
set afterdot1=%%b
)
rem reconstruct first value as fixed point number
set afterdot1=%afterdot1%00000
set afterdot1=%afterdot1:~0,6%
set value1=%beforedot1%%afterdot1%
rem split second value into whole and fractional parts
for /f "tokens=1,2 delims=." %%a in ("%value2%") do (
set beforedot2=%%a
set afterdot2=%%b
)
rem reconstruct second value as fixed point number
set afterdot2=%afterdot2%00000
set afterdot2=%afterdot2:~0,6%
set value2=%beforedot2%%afterdot2%
rem subtract values
set /a diff=value1-value2
rem convert fixed point value back
if "%diff:~0,-6%" == "" (
set diff=0.%diff:~-6%
) else (
set diff=%diff:~0,-6%.%diff:~-6%
)
rem remove trailing zeros
:loop
if "%diff:~-1%" == "0" (
set diff=%diff:~0,-1%
goto :loop
)
echo %diff%

Converting time to seconds using arithmetic operators

I'm trying to convert a time value from a text file from hr:min:sec.sec to just seconds. I have a file with event numbers (consecutive order, 1,2,3 etc.) in column 1 of each row and the rest of the row is event data as in my example below. I want to have the user enter two numbers, with which my script grabs the corresponding hr:min:sec of each event and converts into only seconds.
The file format is 4 000-01:04:10.983745 34.56 string1 string_2 (this would be the 4th line, its date/time, a duration in seconds, and two static strings in the next two columns.
I am using a for loop to grab tokens 1, 2, and 3 using : as the delims and then just trimming the strings for the purpose of performing arithmetic.
So %%A should be 4 000-01, %%B should be 04, and %%C should be everything else on the line. Now I just read batch doesn't support decmials, so I can do without them if needed. But this isn't returning anything:
setlocal enabledelayedexpansion enableextension
REM auto-setting event values for testing
set begin=3
set end=4
for /f "tokens=1,2,3 delims=:" %%A in ('findstr /b /c:"!begin![^0-9]" event.txt') do (
set "hr=%%A"
set /A "min=%%B"
set "sec=%%C"
set /A "hr=!hr:~-2!"
set /A "sec=!sec:~0,2!"
set /A "total=(hr*3600)+(min*60)+sec"
echo !total!>>time.txt
)
exit /B
If your file format is:
line 4 000-01:04:10.983745 34.56 string1 string_2
delim - : : .
token 1 2 3 4
var - A B C
A common technic to avoid the leading zero/octal problem is to prefix
a two place decimal with a literal 1 and subtract 100.
Set /A allows multiple calculations on a line seperated by a comma, the vars don't need to be enclosed in percent signs (doesn't apply to for/arg vars).
#Echo off
setlocal enabledelayedexpansion enableextensions
for /f "tokens=2-4 delims=-:." %%A in (
'findstr /b /C:"4 " event.txt'
) do Set /A "hr=1%%A-100,min=1%%B-100,sec=1%%C-100,total=hr*3600+min*60+sec"
echo Total is %total% (hr=%hr%, min=%min%, sec=%sec%)
echo %total% >>time.txt
exit /B
Sample output:
Total is 3850 (hr=1, min=4,sec=10)
Here is an approach that regards the fractional seconds also, rounded to six fractional figures:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=event.txt"
set "_TARGET=time.txt"
set "_REGEX=^[0-9][0-9]* [0-3][0-9][0-9]-[0-9][0-9]:[0-5][0-9]:[0-5][0-9].[0-9][0-9]* "
rem // Convert filtered lines:
> "%_TARGET%" (
for /F "tokens=1-9* delims=:.- " %%A in ('findstr /R /C:"%_REGEX%" "%_SOURCE%"') do (
rem // Extract and store hour, minute, second values:
set "HOUR=1%%C" & set "MIN=1%%D" & set "SEC=1%%E"
rem // Extract and store fractional seconds and also the static strings:
set "FRAC=1%%F0000000" & set "STR1=%%I" & set "STR2=%%J"
rem // Convert hour, minute, second values to decimal integers:
set /A "HOUR%%=100, MIN%%=100, SEC%%=100"
setlocal EnableDelayedExpansion
rem // Convert fractional seconds to decimal number:
set /A "FRAC=!FRAC:~,7!%%1000000+!FRAC:~7,1!/5"
rem // Compute integer seconds, round to 6 decimal places:
set /A "SEC+=60*(MIN+60*HOUR)+FRAC/1000000" & set "FRAC=000000!FRAC!"
rem // Rebuilt line with time value replaced by fractional seconds:
echo %%A %%B-!SEC!.!FRAC:~-6! %%G.%%H !STR1! !STR2!
endlocal
)
)
endlocal
exit /B

Batch script How to add space on a numerical variable

First of approaches, excuse me if I do not express myself well in English.
I'm debutante in batch and I need help to make a script
I articles.txt retrieves a document in which there are many lines.
some lines of my document
"T0047" ;"Tuyau 1km";"Marque2";"jardinage";"75 000";"promo"
"T00747";"Tuyau 1m";Marque2";"jardinage";"30 000";"promo"
First, I have to remove the quotation marks in the file.
It is done with:
#echo off
setlocal enabledelayedexpansion
for /F "delims=" %%a in (articles.txt) do (
set a=%%a
set a=!a:"=!
echo !a!
echo !a! >>resultat.txt
)
the result
T0047 ;Tuyau 1km;Marque2;jardinage;75 000;promo
T00747;Tuyau 1m;Marque2;jardinage;30 000;promo
Then I have to perform a multiplication on a column.
For this, I have the problem that if the space is not so mutiplication realize I made a script that removes spaces.
#echo off
setlocal enabledelayedexpansion
for /F "delims=; tokens=1-8" %%a in (resultat.txt) do (
set a=%%e
set a=!a: =!
echo %%a;%%b;%%c;%%d;!a!;%%f;%%g;%%h
echo %%a;%%b;%%c;%%d;!a!;%%f;%%g;%%h >>resultat2.txt
)
the result
T0047 ;Tuyau 1km;Marque2;jardinage;75000;promo
T00747;Tuyau 1m;Marque2;jardinage;30000;promo
Then I made my multiplication.
#echo off
setlocal enabledelayedexpansion
for /F "delims=; tokens=1-8" %%a in (resultat2.txt) do (
set a=%%e
:: set /a a=!a!/0.6
set /a a=!a!*16666/10000
echo %%a;%%b;%%c;%%d;!a!;%%f;%%g;%%h
echo %%a;%%b;%%c;%%d;!a!;%%f;%%g;%%h >>resultat3.txt
)
the result
T0047 ;Tuyau 1km;Marque2;jardinage;124995;promo
T00747;Tuyau 1m;Marque2;jardinage;49998;promo
Now, i add some text just after the first colomn
set champ2=MAGASIN_1;T
for /F "delims=; tokens=1,*" %%a in (resultat3.txt) do (
echo %%a;%champ2%;%%b
echo %%a;%champ2%;%%b >>resultat_final.txt
)
The actual result is:
T0047 ;MAGASIN_1;T;Tuyau 1km;Marque2;jardinage;124995;promo
T00747;MAGASIN_1;T;Tuyau 1m;Marque2;jardinage;49998;promo
Now I would add a space so that the figure is more readable.
T0047 ;MAGASIN_1;T;Tuyau 1km;Marque2;jardinage;124 995;promo
T00747;MAGASIN_1;T;Tuyau 1m;Marque2;jardinage;49 998;promo
This is the way I would do it:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%A in (articles.txt) do (
set "a=%%A"
set a=!a:"=!
for /F "delims=; tokens=1-8" %%a in ("!a!") do (
set /A "g1=%%g*16666/10000"
set "g2="
for /L %%i in (1,1,3) do if defined g1 (
set "g2= !g1:~-3!!g2!"
set "g1=!g1:~0,-3!
)
echo %%a;%%b;%%c;%%d;%%e;%%f;!g2:~1!;%%h
echo %%a;%%b;%%c;%%d;%%e;%%f;!g2:~1!;%%h >> result.txt
)
)
articles.txt:
"T0047" ;"MAGASIN_1";"T";"Tuyau 1km";"Marque2";"jardinage";"75000";"promo"
"T00747";"MAGASIN_1";"T";"Tuyau 1m";Marque2";"jardinage";"30000";"promo"
result.txt:
T0047 ;MAGASIN_1;T;Tuyau 1km;Marque2;jardinage;124 995;promo
T00747;MAGASIN_1;T;Tuyau 1m;Marque2;jardinage;49 998;promo
Your program is good. Some tips:
Don't divide by a power of 10. Instead, remove the fractional part if you don't want it. Use *= . And to get the space in the number:
#echo off
set x=75000
set /a x *= 16666
set x=%x:~0,-4%
echo %x:~0,-3% %x:~-3%
I'll respond only to the multiplication section.
I can see nothing in your code that can possibly generte the two extra columns ;MAGASIN_1;Tand consequently, the target field 75000 and 30000 are in %%g, not %%e.
Comment : Do not use the "broken label" comment form ::comment within a block statement (a parenthesised series of statements) because it can terminate the block prematurely. Always use rem with a block.
So - modified code working on %%g
set a=%%g
rem set /a a=!a!/0.6
REM set /a a=!a!*16666/10000
set /a a=!a!*10/6
SET "a= !a:~-9,-6! !a:~-6,-3! !a:~-3!"
FOR /f "tokens=*" %%q IN ("!a!") DO SET "a=%%q"
echo %%a;%%b;%%c;%%d;%%e;%%f;!a!;%%h
Reason: Batch has a signed-32-bit limit, so if the source field is >~120000 then your calculation will generate a negative number (try 130000 for example) The revised calculation is more accurate and since intermediate results are less likely to exceed 2**31 can cope with larger values in the %%g field.
The set following the calculation changes the numeric value in a to
space(millions)space(thousands)space(units)
(The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".)
The for /f "tokens=*"... statement simply removes leading spaces from the value of a.
With the explanatin of the two additional columns, This revision should solve the "add-spaces" problem:
set a=%%e
rem set /a a=!a!/0.6
REM set /a a=!a!*16666/10000
set /a a=!a!*10/6
SET "a= !a:~-9,-6! !a:~-6,-3! !a:~-3!"
FOR /f "tokens=*" %%q IN ("!a!") DO SET "a=%%q"
echo %%a;%%b;%%c;%%d;!a!;%%f;%%g;%%h
however, if you want to skip the last step (insertion of 2 extra fields) then insert this line before the for line in the "multiplication" batch
set champ2=MAGASIN_1;T
and change the echo line in that batch to
echo %%a;%champ2%;%%b;%%c;%%d;!a!;%%f;%%g;%%h
Since you have a semicolon-delimited list of values where each item is enclosed within quotation marks, I would go for a standard for to get the items of each line and remove the enclosing quotation marks. The great advantage of this method is that it really cares about the quotation marks, so the list items may even contain semicolons on their own. The only disadvantage is that question marks and asterisks are not allowed in any of the list items:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Redirect all data to output file "resultat.txt" at once:
> "resultat.txt" (
rem Loop through all (non-empty) lines of input file "articles.txt":
for /F "usebackq delims=" %%L in ("articles.txt") do (
rem Reset list collector and loop index:
set "LIST="
set /A "INDEX=0"
rem Loop through the list items of the current line:
for %%I in (%%L) do (
rem Apply current list item with `""` removed, increment loop index:
set "ITEM=%%~I"
set /A "INDEX+=1"
rem Do numeric calculation for a certain list item:
setlocal EnableDelayedExpansion
if !INDEX! EQU 5 (
rem Convert item to a number, avoid error messages:
2> nul set /A "CALC=!ITEM!"
rem Do calculation with rounding (for negative and positive numbers):
if !CALC! LSS 0 (
set /A "CALC=(!CALC!*10-6/2)/6"
) else (
set /A "CALC=(!CALC!*10+6/2)/6"
)
rem Insert thousands separators (space) between every third digit:
set "CALC=!CALC:~-12,-9! !CALC:~-9,-6! !CALC:~-6,-3! !CALC:~-3!"
for /F "tokens=*" %%N in ("!CALC!") do (
set "ITEM=%%N"
)
)
rem Append separator (semicolon) and current item to list:
for /F delims^=^ eol^= %%S in ("!LIST!;!ITEM!") do (
endlocal
set "LIST=%%S"
)
)
rem Return built list, remove superfluous leading separator (`;`):
setlocal EnableDelayedExpansion
echo(!LIST:~1!
endlocal
)
)
endlocal
exit /B
The calculation herein incorporates rounding to the nearest integer, which works even for negative input numbers.
The newly generated list is stored into the new file resultat.txt.

How to count the ones in a binary representation of a given hex in a cmd Batch?

i am trying to write a batch file that asks the user to type a hexadcimal number and then counts the number of ones in the binary representation , like if i typed A the program echos 1 .
i have this code that uses a look up table to convert from binary to hex and answered by Aacini here ...
#echo off
setlocal
set "bin=110111101010110110111110111011111100101011111110"
call :bin2hex hex=%bin%
echo hex: %hex%
goto :EOF
:bin2hex hexVar=binValue
setlocal EnableDelayedExpansion
for %%a in (0000-0;0001-1;0010-2;0011-3;0100-4;0101-5;0110-6;0111-7;1000-8;1001-9;1010-A;1011-B;1100-C;1101-D;1110-E;1111-F) do (
for /F "tokens=1,2 delims=-" %%b in ("%%a") do (
set "hextable[%%b]=%%c"
)
)
set "hex="
set "bin=000%~2"
:bin2hexloop
set "hex=!hextable[%bin:~-4%]!%hex%"
set "bin=%bin:~0,-4%"
if defined bin if "%bin:~3%" neq "" goto bin2hexloop
endlocal & set "%~1=%hex%"
goto :EOF
i tried to inverse the way this code works , but it didn't work !
here is my attempt
#echo off
setlocal
set "hex=ABCDEF"
call :hex2bin bin=%bin%
echo : %bin%
pause;
goto :EOF
:hex2bin binVar=hexValue
setlocal EnableDelayedExpansion
for %%a in (0-0000;1-0001;2-0010;3-0011;4-0100;5-0101;6-0110;7-0111;8-1000;9-1001;A-1010;B-1011;C-1100;D-1101;E-1110;F-1111) do (
for /F "tokens=1,2 delims=-" %%b in ("%%a") do (
set "bintable[%%b]=%%c"
)
)
set "bin="
set "hex=000%~16"
:hex2binloop
set "bin=!bintable[%hex:~-4%]!%bin%"
set "hex=%hex:~0,-4%"
if defined hex if "%hex:~3%" neq "" goto hex2binloop
endlocal & set "%~4=%bin%"
goto :EOF
anybody can help me ?
If I understood you correctly, you want not to "convert a hexadecimal number to binary", but to "count the ones that each hex digit have" and accumulate they (for example, for A the number is 1). This way, the solution must work with "The number of ones each hex digit have".
#echo off
setlocal
set "hex=ABCDEF"
call :countOnesInHex ones=%hex%
echo There are %ones% ones in %hex%
pause
goto :EOF
:countOnesInHex ones=hexValue
setlocal
for %%a in (0-0;1-1;2-1;3-2;4-1;5-2;6-2;7-3;8-1;9-2;A-2;B-3;C-2;D-3;E-3;F-4) do (
for /F "tokens=1,2 delims=-" %%b in ("%%a") do (
set "onesIn[%%b]=%%c"
)
)
set ones=0
set "hex=%~2"
:hexCountLoop
set /A ones+=onesIn[%hex:~0,1%]
set "hex=%hex:~1%"
if defined hex goto hexCountLoop
endlocal & set "%1=%ones%"
exit /B
Convert the number to decimal and do the basic math: divide by 2 and sum the remainders.
Do it in chunks of 7 hexadecimal digits because batch file calculations support only 31 bits (2^31-1 or 2147483647 or 0x7FFFFFFF).
set hex=ABCDEFABCDEFABCDEF
set ones=0
:loopchunks
set /a decimal=0x%hex:~0,7%
set hex=%hex:~7%
:loopdigits
set /a ones+=decimal %% 2, decimal/=2
if not %decimal%==0 goto loopdigits
if defined hex goto loopchunks
echo %ones%
Output:
51
#ECHO OFF
SETLOCAL
FOR %%a IN (F37ABD abcdef 123 321 99 100 f11f 0 cafe) DO CALL :mainproc %%a
GOTO :eof
:mainproc
SET hexnum=%1
SET /a count1=0
:loop
SET /a hex1=0x%hexnum:~0,1%
:bitloop
SET /a count1+=%hex1% %% 2
SET /a hex1/=2
IF %hex1% gtr 0 GOTO bitloop
SET hexnum=%hexnum:~1%
IF DEFINED hexnum GOTO loop
ECHO %count1% 1s detected IN %1
GOTO :EOF
The for loop simply assigns the values in the list to the variable %%a in turn and executes the main part of the procedure with a parameter (%1) of that item.
Within the main procedure, initialise hexnum as the number to be analysed and count1 with the accumulated number of 1s
Then set hex1 to 0xstrung before (copy the first digit of hexnum) which will be a hex numeric, 0x0 to 0xf. SInce this is the format for cmd to accept a hex number, it sets hex1 to decimal 0..15
next add (hex1 mod 2) to count, that is 1 or zero if odd/even
next halve hex1. Since cmd calculates in integer mode, the result is truncated, hence 6=>3 and 7+>3
the result is >0, do the next binary digit. repeat until 0.
Toss out the first character of hexnum (assign the substring starting at character 1, given that it starts counting at "character 0")
If hexnum has characters left, repeat for the next hex digit
otherwise, report.
result:
17 1s detected IN F37ABD
17 1s detected IN abcdef
4 1s detected IN 123
4 1s detected IN 321
4 1s detected IN 99
1 1s detected IN 100
10 1s detected IN f11f
0 1s detected IN 0
11 1s detected IN cafe

Floating point division in a batch file

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 ?
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
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.
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.
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…
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
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.)
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%"^)
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

Resources