Accuracy of Decimals in a Batch Program - batch-file

Trying to create a batch program (I have no other option but only use batch) that can accept a decimal input, the input is only specific up to two decimal places. My problem is how I can round-off the output to improve accuracy. For example the user input is 100.77*0.80, the answer is 80.616, I can only output 80.61 and not 80.616, I want an output of 80.62. And my bigger problem is that the decimal answer will be used to subtract from the original amount which will cause a Mathematical mistake in the decimal level. The answer will be 80.61 and 20.16.
Here's my program:
#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"
:getFee
set /P "Amt=Enter the Amount (100.00): "
set /P "Disc=Enter the Discount Percentage: "
if "!Amt:~-%decimalsP1%,1!" equ "." goto AmtDeci
:getNumber
goto NoDeci
:AmtDeci
set "fpA=%Amt:.=%"
set "fpB=%Disc:.=%"
set /A mul=fpA*fpB/one
set discout=!mul:~0,-2!.!mul:~-2!
echo The Discount is: %discout%
set /A "fpD=%discout:.=%"
set /A sub=fpA-fpD
set Amtout=!sub:~0,-%decimals%!.!sub:~-%decimals%!
echo The Amount less discount is: %Amtout%
pause
Exit /B
:NoDeci
set /a discout=%Amt%*%Disc%/100
set /a Amtout=%Amt%-discout
echo The Amount less Discount is: %Amtout%
echo The Discount is: %discout%
pause

I assume you are using the method described at this answer. You always should include a link to the original source of your code.
What you want to do is very simple: just add the equivalent of 0.5 to the result of the multiplication before divide it by one:
set /A mul=(fpA*fpB+50)/one
Output example:
Enter the Amount (100.00): 100.77
Enter the Discount Percentage: 80
The Discount is: 80.62
The Amount less discount is: 20.15

Related

Basic BAT calculator command

I am trying to do a very basic 2 value input BAT file but I am struggling. I used a free template from Wikihow and re-adjusted but something is not right.
I want to calculate 100/(A/B+1) and I know for a fact that the Batch calculation ignores the "+1" for some reason and basically just calculates "100/(A/B). Please help. Thanks.
TITLE Calculator
ECHO OFF
CLS
:TOP
color 3f
Cls
:SUM
CLS
ECHO ---------------------------------------------------
ECHO[
ECHO Division
ECHO[
ECHO ---------------------------------------------------
ECHO[
set /p A=" Enter First Amount = "
ECHO[
set /p B=" Enter Second Amount = "
SET /A C=100/(A/B+1)
ECHO[
ECHO ---------------------------------------------------
ECHO Result %C%
PAUSE
GOTO:TOP
I suspect this is an order of operations issue.
Remember that plus comes after division.
You might need this instead:
SET /A C=100/(A/(B+1))
This will allow the B+1 to come before the division.
SET /A doesn't ignore the +1:
E.g. SET /A 100/(10/2+1) outputs 16; the problem you most likely have is this:
Any SET /A calculation that returns a fractional result will be
rounded down to the nearest whole integer.
(Source)
However, it is possible to work around this issue:
SETLOCAL EnableDelayedExpansion
SET /A "var=100000/(10/2+1)"
SET "fraction=%var:~-3%" & SET /A "var/=1000"
IF !fraction:~-1! GEQ 5 SET /A "fraction+=10"
SET "fraction=!fraction:~0,-1!"
ECHO %var%.%fraction%
Basically you multiply the number to be divided by 10^(n) and - after you set the fraction (%var:~-n%) - divide it by 10^(n) again. Then you check the last digit of the fraction for proper rounding and remove it (read more).
I am assuming you were looking for:
SET /A C=(A/B)+1
SET /A C=100/(C)
This the correct formula, but it will not return the correct results for fractioned numbers.
So if A = 10 and B = 2
10 / 2 = 5 +1 =6
100/6 = 16,6 but batch rounds off to 16.
Then A = 453 and B = 178
453 / 178 = 2,544943820224719
2,544943820224719 + 1 = 3,544943820224719 but Batch rounds off to 3
100/3 = 33
So if you use numbers that will cause fractions, you MUST use a solution that include fractions.

Simple math program wont work?

I'm trying to create a batch program that will add the input to 232, then divide the result by 470. It would also be nice if someone told me how to make it so that if the user inputs a letter instead of a number, or an invalid character, anything besides a number, the program would execute a "goto command." Thanks!
PS the current code outputs 0, regardless of input.
Heres my code:
#echo off
title Grade
:1
cls
set /p input= "Grade: "
set /a input1= input + 232
set /a input2= input1 / 470
echo %input2%
pause
goto 1
For your division equation, batch files do not support floating point arithmetic, so you won't get a true answer. Anything less than 238 for input returns a 0 for your quotient.
Here's some code to let you see how to guarantee numeric input.
:Blurb
#Echo off
Cls
Echo Grade Math
:GetNum
Echo.
Set /p _Input="Grade: "
Set "_Num="
For /f "delims=0123456789" %%i in ("%_Input%") Do Set "_Num=%%i"
If Defined _Num Echo.&Echo Invalid: please enter a number.&Goto :GetNum
:DoMath
Set /a _Sum= _Input + 232
Echo Sum = %_Sum%
Set /a _Quotient= _Sum / 470
Echo Quotient = %_Quotient%
Pause
Goto :GetNum
:End

Batch does not compute equations properly

I recently tried to write a program in batch that calculates square root of any real number (instead of negative numbers) without using external commands or tools and the program is based on the algorithm that can be found here: Link1
EDIT: Most of the problem I fixed, but there is still a slight undetected by me problem.
Please run this 'debug mode' code: Link2 and test the output for number 15625 and precision 3.
In order for the code to be correct, the debug code has to display:
- finalpart: 1
2
adder: 56
- finalpart: 44
3
adder: 25
- finalpart: 1225
4
adder: 0
Answer: 125
Excuse me. If you want that we review your code looking for errors I can not help you. Your code is large and have not a single descriptive comment, and several variable names are confusing and prone to cause editing errors. I reviewed your link to the Wikipedia article and the method seemed interesting to me, but when I compared the described method with your program the code seemed unnecessarily complex, so I decided to write my own version of that method; I apologize if this is not what you asked for.
In this program the precision is set to the number of decimals / 2 of the input number, but a very simple modification would allow to set it to a fixed number. I tested this program with multiple numbers and works correctly.
#echo off
setlocal
:nextNumber
set "number="
set /P "number=Number: "
if not defined number goto :EOF
call :SquareRoot %number% sqrt=
echo Square root: %sqrt%
echo/
goto nextNumber
:SquareRoot number result=
setlocal EnableDelayedExpansion
rem Separate the number in aligned blocks of 2 digits each
for /F "tokens=1,2 delims=." %%a in ("%1") do set "int=%%a" & set "frac=%%b"
set /A i=11, f=10
:nextInt
if not defined int goto nextFrac
set /A i-=1
set "block[%i%]=%int:~-2%"
set "int=%int:~0,-2%"
goto nextInt
:nextFrac
if not defined frac goto checkLastBlock
set /A f+=1
set "block[%f%]=%frac:~0,2%"
set "frac=%frac:~2%"
goto nextFrac
:checkLastBlock
if %f% gtr 10 if "!block[%f%]:~1!" equ "" set "block[%f%]=!block[%f%]!0"
rem Get square root of first block: digit between 0 and 9
set /A num=block[%i%], iP1=i+1, addZeros=0
for /L %%r in (0,1,9) do (
set /A r2=%%r*%%r
if !r2! leq %num% set /A sqrt=%%r, remainder=num-r2
)
rem Get square root of next blocks
for /L %%i in (%iP1%,1,%f%) do (
set /A remainder1=remainder*10+!block[%%i]:~0,1!, remainder2=remainder*100+1!block[%%i]!-100, sqrtT2=sqrt*2
if !sqrtT2! equ 0 (
rem The number started with zeros: no sqrt yet
set "sqrt="
set /A addZeros+=1
for /L %%r in (0,1,9) do (
set /A r2=%%r*%%r
if !r2! leq !remainder2! set /A nextDigit=%%r, remainder=remainder2-r2
)
) else if !remainder1! lss !sqrtT2! (
rem There is no sqrt for this block
set /A nextDigit=0, remainder=remainder2
) else (
set /A nextDigit=remainder1/sqrtT2, test=sqrtT2*10+nextDigit, this=test*nextDigit
if !this! gtr !remainder2! (
rem Next digit is too large: decrease it
set /A "times=(this-remainder2)/test+1"
for /L %%t in (1,1,!times!) do if !this! gtr !remainder2! (
set /A nextDigit-=1, test=sqrtT2*10+nextDigit, this=test*nextDigit
)
)
set /A remainder=remainder2-this
)
set "sqrt=!sqrt!!nextDigit!"
)
for /L %%i in (1,1,%addZeros%) do set "sqrt=0!sqrt!"
set /A point=11-i
set "sqrt=!sqrt:~0,%point%!.!sqrt:~%point%!"
endlocal & set "%2=%sqrt%"
exit /B
Output example:
Number: 15625.000000
Square root: 125.000
Number: 625
Square root: 25.
Number: 64
Square root: 8.
Number: 9
Square root: 3.
Number: 0.25
Square root: 0.5
Number: 987654321987654321
Square root: 993807990.
Number: 1234567890123456789
Square root: 1111111106.
Number: 2.000000000000000000
Square root: 1.414213562
This code shows 30 decimal of the square root.
here is My Way :
#echo off
title SQR
set /p x=PLS Enter Your Number =
echo.
echo Wscript.Echo (FormatNumber(SQR(Wscript.Arguments(0)),30))>Q.vbs
cscript //nologo Q.vbs %x% & DEL "Q.vbs"
PAUSE>NUL

How to make %random% show up a negative result?

I'm making a game where there are stocks, and I want them to be able to go negative, I know how to limit the positive random numbers, but how do I get the %random% to make a negative value? And, is making the %random% generate negative numbers even possible?
Just subtract the random number from 0.
set /a negative_random=0-%random%
To produce a random number in the range minrand to maxrand use
SET /a selection=%RANDOM% %% (%maxrand% - %minrand% + 1) + %minrand%
Here's a sampler : change the values assigned to minrand and maxrand to test:
#ECHO OFF
SETLOCAL
SET /a minrand=-3
SET /a maxrand=3
FOR /l %%a IN (1,1,20) DO CALL :genshow
GOTO :eof
:genshow
SET /a selection=%RANDOM% %% (%maxrand% - %minrand% + 1) + %minrand%
ECHO %selection%
GOTO :EOF
It depends on the range you want. If [-16384, 16383] is enough for you, use this
set /a num=%random%-16384
Otherwise if you need random values in the range [a, b] then use this
set /a num=%random% %%(b-a+1) + a
For example to get values from -10 to 20, use this
set /a num=%random% %%31 - 10

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