How to make %random% show up a negative result? - batch-file

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

Related

How to make random number variable with variables within it?

So I've been trying to make the following code:
set /a num1=10
set /a num2=%random% %%60 +%num1%
echo %num2%
(This is simplified)
For this code I need the +%num1% to be a variable because I need to be able to change the lowest number.
For some reason, instead of giving me a random number it gives a totally unrelated number, that isn't random either, but the same every time. My first thought was it was perhaps adding the second variable instead of making a randomizer. That is not the case though, and I'm not sure how to fix this issue.
I have also tried the following code:
set /a num1=10
set /a num2=(%random%*60/32768)+%num1%
echo %num2%
The issue with this code is it never seems to work as randomizer for me even without the variable.
Any help is appreciated.
Here's some examples to assist you:
Set "num1=10"
Set /A "num2 = (%RANDOM% %% 60) + num1"
Echo(%num2%
Set "num1=10"
Set /A "num2 = (%RANDOM% * 60 / 32768) + num1"
Echo(%num2%
Please note, that we have only been provided with a very small portion of your batch file, so if this code is part of a parenthesized block, you may need to enable delayed expansion and use !RANDOM! and possibly !num2! instead of %RANDOM% and %num2% respectively.
In the first form you are have to account for modulus bias, as described further in this question Why do people say there is modulo bias when using a random number generator?
(Note: the accepted answer there has a flaw which I pointed out and provide a solution to in my answer to that question.)
In both the first and the second form they present an incorrect range of values the way it is written. More info can be found here How to use random in BATCH script?
Long story Short:
In both forms, if you want your range to start at 10 and go to 60 you will need to adjust it to be using a modulus of 50, in the first form you must account for modulus bias in your calculations causing some numbers to appear more often.
The first form can be fixed using this method:
SET "Min=10"
SET "Max=60"
SET /A "Discard= 32768 - ( ( ( 32768 %% (Min-Max) ) + 1 ) %% (Min-Max) )"
:Rand
SET /A "num2=%random%"
IF %num2% GTR %Discard% GOTO :Rand
SET /A "num2= num2 %% (Min-Max) + Min"
echo=%num2%
The second form can be fixed using this method:
SET "Min=10"
SET "Max=60"
SET /A "num2= %random% * ( Max - Min + 1 ) / 32768 + Min "
echo=%num2%
Example of Full script:
#(SETLOCAL
ECHO OFF
)
CALL :Main
( ENDLOCAL
EXIT /B
pause
)
:Main
SET "Min=10"
SET "Max=60"
SET /A "Discard= 32768 - ( ( ( 32768 %% (Min-Max) ) + 1 ) %% (Min-Max) )"
ECHO=Form1:
CALL :Form1
ECHO=Form2:
CALL :Form2
pause
GOTO :EOF
:Form1
SET "num2=%random%"
IF %num2% GTR %Discard% GOTO :Form1
SET /A "num2= num2 %% ( Min - Max ) + Min"
echo=%num2%
GOTO :EOF
:Form2
SET /A "num2= %random% * ( Max - Min + 1 ) / 32768 + Min "
echo=%num2%
GOTO :EOF
Results:
C:\WINDOWS\system32>C:\Admin\SE\testrandom.cmd
Form1:
10
Form2:
31
Press any key to continue . . .
C:\WINDOWS\system32>

How can I make a random number/letter generator?

Hello guys I am very bad at notepad, I want to make a random code generator.
That Generates codes like this 3K2EU-ZGS5L-P3DNL-YM9JC
I want it to work with a notepad .bat file so I can let it run on my PC
This can be done using %random% values to assign numbers and letters as demonstrated
below. If you need letters and numbers in specific places within the 20 digits,
adjust the Condition used to call getLetters or Getnumber to call according to current
%dig%==number
#ECHO OFF
SETLOCAL enableDelayedExpansion
:open
Set dig=0
:main
Set /a dig=%dig% + 1
CALL :digit%dig%
Call LetorNum
IF %dig%==20 goto result
GOTO main
:LetorNum
Set /a pick=%random% * 2 / 32768 + 1
IF %pick%==1 call :getLetter
IF %pick%==2 call :getNumber
GOTO :EOF
:getLetter
Set /a Letter=%random% * 26 / 32768 + 1
IF %letter%==1 Set disp!dig!=a
REM repeat for each letter value between a and z
IF %letter%==26 Set disp!dig!=z
GOTO :EOF
:getNumber
Set /a number=%random% * 10 / 32768 + 1
IF %number%==1 Set disp!dig!=0
REM repeat for every number value between zero and 9
IF %number%==9 Set disp!dig!=9
GOTO :EOF
:result
ECHO %disp1%%disp2%%disp3%%disp4%%disp5%-%disp6%%disp7%%disp8%%disp9%%disp10%-
%disp11%%disp12%%disp13%%disp14%%disp15%-%disp16%%disp17%%disp18%%disp19%%disp20%
pause >nul
GOTO open

How to increase alphabetic variable - Batch

I was able to increase the number variable:
SET /a Y=0
SET /a Y+=1
ECHO %Y% = 1
But I want to "increase" the variable with letters.
Ex:
SET Y=A
SET Y+=1
ECHO %Y% = B
Anyway to do something like this in Batch?
Only with a sort of fake pointer.
#Echo off
Setlocal EnableDelayedExpansion
Set "Letters=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Set I=25
SET Y=!Letters:~%I%,1!
Echo Y=%Y%
SET /A I+=1,I=I %% 26
SET Y=!Letters:~%I%,1!
Echo Y=%Y%
To have the algorythm continue with A again after reaching Z, you've to calculate the modulus 26
Y=Z
Y=A

How to find large factorials using a batch script

#echo off
if %1.==. ( echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end )
setlocal enabledelayedexpansion
set /a count=0
set /a temp=0
set /a digits=1
set /a array1=1
for /L %%i IN (2,1,%1) do (
set /a temp=0
for /L %%j IN ( 1,1,!digits! ) do (
set /a temp=!temp!+!array%%j!*%%i
set /a array%%j=!temp!%%10
set /a temp=!temp!/10 )
set /a index=!digits!+1
for /L %%v IN (!index!,1,!index! ) do (
if !temp! NEQ 0 (
set /a array!index!=!temp!%%10
set /a temp/=10
set /a index+=1 ))
set /a digits=!index!-1)
for /l %%v IN ( !digits!,-1,1 ) do set array=!array!!array%%v!
echo !array!
echo Total # of decimal digits = !digits!
:end
pause
This is what i have gotten so far. It is quite stable under 10! but once i reach 15 or 20 it starts missing out a few digits.
My edit....
#echo off
if %1.==. ( echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end )
setlocal enabledelayedexpansion
set /a count=0
set /a temp=0
set /a digits=1
set /a array1=1
for /L %%i IN (2,1,%1) do (
set /a temp=0
for /L %%j IN ( 1,1,!digits! ) do (
set /a temp=!temp!+!array%%j!*%%i
set /a array%%j=!temp!%%10
set /a temp=!temp!/10 )
for /l %%v IN ( 1,1,30 ) do (
if !temp! neq 0 (
set /a digits+=1
set /a array!digits!=!temp!%%10
set /a temp=!temp!/10
)))
for /l %%v IN ( !digits!,-1,1 ) do set array=!array!!array%%v!
echo !array!
echo Total # of decimal digits = !digits!
:end
pause
Now i am forcing the the last inner loop to run 30 times eventhough temp would have been zero way before that. Is there any way to write a snippet that would be analogous to the following c code
while (temp)
{/code goes here/}
This execute only as long as temp is non zero.
Is there any partyicular limit to how big a variable can be in a batch?
I know it is a pain * to debug computational programs in a batch, I'm just trying to code this in all programming languages i know, Just so i could compare their speeds. Can somebody Please point out what i'm doing wrong here.
edit........22/12/13
#echo off
if %1.==. ( echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end )
setlocal enabledelayedexpansion
set /a count=0
set /a tempo=0
set /a digits=1
set /a array1=1
for /f "tokens=1-4 delims=:.," %%a IN ("%time%") do (
set /a "start=(((%%a*60)+1%%b %% 100)*60+1%%c %%100)*100+1%%d %% 100"
)
for /L %%i IN (2,1,%1) do (
set /a tempo=0
for /L %%j IN ( 1,1,!digits! ) do (
set /a tempo=!tempo!+!array%%j!*%%i
set /a array%%j=!tempo!%%10000
set /a tempo=!tempo!/10000 )
for /l %%v IN (1,1,2) do (
if !tempo! neq 0 (
set /a digits+=1
set /a array!digits!=tempo%%10000
set /a tempo=tempo/10000
))
)
for /l %%v IN ( !digits!,-1,1 ) do set array=!array!!array%%v!
echo !array!
echo Total # of decimal digits = !digits!
for /f "tokens=1-4 delims=:.," %%a in ("%time%") do (
set /a "end=(((%%a*60)+1%%b %% 100)*60+1%%c %%100)*100+1%%d %% 100"
)
set /a elapsedcs=end-start
set /a elapseds=elapsedcs/100
set /a elapsedcs=elapsedcs%%100
echo %elapseds%.%elapsedcs% seconds
:end
rem label should never be the last statement
Is this what you meant aacini?
In order to achieve fast arithmetic operations on Big numbers in Batch, you must split the Bignum in groups of digits that can be managed via the 32-bits operations of set /A command. The maximum 32-bits signed integer is 2147483647, so the largest group of digits that can be multiplied this way is 4, because 5 digits (99999 x 99999) exceed the maximum number. Addition and multiplication must be achieved from right to left translating a "carry" to the next group to the left. Subtraction and division must be achieved from left to right translating a "borrow" to the next group to the right. The Batch file below use this method to succesively multiply a Bignum by a 4 digits factor, so it can calculate up to 9999! as long as all variables that contain the groups of 4 digits fits in the 64 MB size limit of the environment (look for "65,536KB maximum size" under "Setting environment variables"). The result is directly output to the screen in order to avoid the 8192 digits limit of one Batch variable.
EDIT: I slightly modified the program in order to run faster and get the number of digits in the result.
#echo off
if "%1" equ "" (
echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end
)
setlocal EnableDelayedExpansion
rem Calculate the factorial
set /A g1=1, groups=1
for /L %%n in (2,1,%1) do (
set carry=0
for /L %%g in (1,1,!groups!) do (
set /A group=g%%g*%%n+carry, g%%g=group%%10000, carry=group/10000
)
if !carry! neq 0 (
set /A groups+=1
set g!groups!=!carry!
)
)
rem Show the factorial
set /P "=!g%groups%!" < NUL
set /A groupsM1=groups-1
for /L %%g in (%groupsM1%,-1,1) do (
set group=000!g%%g!
set /P "=!group:~-4!" < NUL
)
echo/
rem Get the number of digits
set digits=0
for /L %%i in (0,1,3) do if "!g%groups%:~%%i,1!" neq "" set /A digits+=1
set /A digits+=4*groupsM1
echo Total # of decimal digits = %digits%
:end
pause
I had to rereread the code to see what it is doing. Nice.
You have to face three limits on your code.
1 - In the inner %%j and %%v loop, where buffer is used to multiply the current value in %%i, you face the limit indicated by Magoo. You can not operate with set /a with values greater than 2^31. As the values in the array are limited to 0-9, this means that this limit will not let you calculate factorials of numbers greater than 214748364 (aprox)
2 - There is a limit in the size of a environment variable. It can not hold more than 32767 characters. As you are concatenating the digits to output to console (the next limit is related), this limits you to factorials of numbers below 9273 (aprox).
3 - There is a limit in the length of the lines cmd can handle. It is 8191 characters. This does not limit your calc, but you can not use the method of concatenating in a variable to represent the number. If the method is not changed, this limits you to factorials of numbers below 2727 (aprox).
Batch is limited to signed-32-bit integers.
BTW - don't use temp or tmp as a user-variable. It is set by the system as a pointer to a directory where temporary files are stored.

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