Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Printing random numbers

76 views
Skip to first unread message

RazTK

unread,
Feb 8, 2006, 6:42:53 PM2/8/06
to
I tried to write a batch file that prints random numbers (from 1 to 296
for example) and I tried to make it so it won't print a number that has
already been shown, this is what I got:

@echo off
:Test
set /a x=%random% %% 296 + 1
for %%? in (%x2%) do if "%x%"=="%%?" goto Test
if "%x2%"=="" (set x2=%x%) else set x2=%x2% %x%
set /a x3+=1
if %x% lss 10 (if %x3% lss 10 (echo. %x% - %x3%) else if %x3% lss
100 (echo. %x% - %x3%) else echo. %x% - %x3%) else if %x% lss 100
(if %x3% lss 10 (echo. %x% - %x3%) else if %x3% lss 100 (echo. %x% -
%x3%) else echo. %x% - %x3%) else if %x3% lss 10 (echo %x% - %x3%)
else if %x3% lss 100 (echo %x% - %x3%) else echo %x% - %x3%
if "%x3%"=="296" (echo.
echo Done.
echo.
pause
goto :eof)
goto Test

Do you have a better way to do this?

Phil Robyn

unread,
Feb 8, 2006, 7:16:38 PM2/8/06
to

How about something like the following?

@echo off
setlocal
set ctr=0
:Test
if %ctr% equ 296 goto :EOF


set /a x=%random% %% 296 + 1

echo/.%x2%. | findstr ".%x%." > nul
if %errorlevel% equ 0 goto :Test
set /a ctr += 1
set x2=%x2% %x%
echo/%x2%
goto :Test

But it will get slower and slower as x2 contains more and more numbers....

--
Phil Robyn
University of California, Berkeley

RazTK

unread,
Feb 8, 2006, 7:41:01 PM2/8/06
to
Yes, you are right... :-|
I can't see any better way to do that.

Harlan Grove

unread,
Feb 8, 2006, 8:48:29 PM2/8/06
to
Phil Robyn wrote...

>RazTK wrote:
>>I tried to write a batch file that prints random numbers (from 1 to 296
>>for example) and I tried to make it so it won't print a number that has
>>already been shown, this is what I got:
...

>>Do you have a better way to do this?
>
>How about something like the following?
>
>@echo off
>setlocal
>set ctr=0
>:Test
>if %ctr% equ 296 goto :EOF
>set /a x=%random% %% 296 + 1
>echo/.%x2%. | findstr ".%x%." > nul
>if %errorlevel% equ 0 goto :Test
>set /a ctr += 1
>set x2=%x2% %x%
>echo/%x2%
>goto :Test
>
>But it will get slower and slower as x2 contains more and more numbers....

%RANDOM% comes from a pseudorandom number generator with a period of
32768. As long as OP doesn't need more than 32768 lines, the OP could
use as follows.

@echo off & setlocal enableextensions enabledelayedexpansion
if .%1. == .. goto USAGE
if .%2. == .. goto USAGE
if .%3. == .. ( set m=1 ) else ( set m=%3 )
copy nul "%0.temp" > nul 2>&1
for /L %%k in (%1,%m%,%2) do (
set /a x=!random!+100000
echo !x:~1! %%k >> "%0.temp"
)
for /F "tokens=2 delims= " %%k in ('sort "%0.temp"') do echo %%k
del "%0.temp"
goto :EOF
:USAGE
echo %0 startnum endnum [stepval]
goto :EOF

It'll slow down as the number of records increases, but the sort
command's O(N log(N)) performance should be noticeably faster. For
arguments 1 5000 it runs in 3-4 seconds on my system.

RazTK

unread,
Feb 8, 2006, 9:28:41 PM2/8/06
to
Very interesting ;-)
Can you tell me how the SORT command works?
And why you did SET /A X=!RANDOM!+100000 and not just SET /A X=!RANDOM!
?

Ted Davis

unread,
Feb 8, 2006, 9:53:24 PM2/8/06
to

wget -O- http://www.random.org/cgi-bin/randseq?min=1^&max=296 2>null

You can get wget for Windows from
<http://users.ugent.be/~bpuype/wget/>

See <http://www.random.org/> for more information about their true
random number/sequence/byte service. Your task is a random sequence.


--
T.E.D. (tda...@gearbox.maem.umr.edu)

RazTK

unread,
Feb 8, 2006, 10:01:16 PM2/8/06
to
Thanks you very much, Ted.
This is my current code:

@echo off
if "%~1"=="" goto Help
if "%~2"=="" goto Help
if "%~3"=="" (set step=1) else set step=%~3
for /l %%? in (%~1 %step% %~2) do echo !random!:%%? >>%~nx0.txt
for /f "tokens=2 delims=:" %%? in ('sort %~nx0.txt') do echo %%?
del "%~nx0.txt"
goto :eof
:Help
echo.
echo %~n0 start stop [step]
goto :eof

Harlan Grove

unread,
Feb 8, 2006, 10:05:34 PM2/8/06
to
RazTK wrote...
...

>Can you tell me how the SORT command works?

I could, but either the command

sort /? | more

or going through the Start Menu, Help and Support and searching for the
sort command would give a much more complete explanation that I'd
provide.

>And why you did SET /A X=!RANDOM!+100000 and not just SET /A X=!RANDOM! ?

DOS sort is relatively simplistic. It's purely text sorting, so 5 would
sort after 1, 22, 370, 4567890123 etc. in ascending order because 5
comes after 1, 2, 3 and 4 in character order. The 2 phase process of
setting x to !RANDOM!+100000 then using !x:~1! effectively ensures that
the resulting output records' first field always has 5 decimal digits
possibly with leading zeros. 00005 will sort *before* 00022, 00370 etc.
(4567890123 would be a bit beyond the problem scope I assumed) in
ascending order. When using a sorting tool that lacks numeric
semantics, padding with leading zeros is the next best thing.

RazTK

unread,
Feb 8, 2006, 10:14:15 PM2/8/06
to
I understand, thank you very much! :-)

b.ped...@get2net.dk

unread,
Feb 9, 2006, 12:57:29 AM2/9/06
to
@echo off& setlocal enableextensions

set /p low= Input Lowerbound:
set /p upp= Input Upperbound:

call:_random "cscript.exe" "%tmp%\tmp.vbs" "%low%" "%upp%"
echo Random Number is: %r%& pause& goto:eof

:_random
echo>%2 randomize:wscript.echo int^(^(%4-%3+1^)*rnd+%3^)
(for /f %%r in ('%~$path:1 %2')do set r=%%r)& del %2

goto:eof
OR goto:Examples

Benny Pedersen,
PS: the %~$path:1 returns the full path of cscript.exe
:Examples

echo.... 1: %~$path:1
echo.... 2: %~dp$path:1%~1
for %%f in (%~1)do (
echo.... 3: %%~$path:f
echo.... 4: %%~dp$path:f%~1
echo.... 5: %%~dp$path:f%%f
)

Harlan Grove

unread,
Feb 9, 2006, 2:04:54 AM2/9/06
to
b.ped...@get2net.dk wrote...
...

>call:_random "cscript.exe" "%tmp%\tmp.vbs" "%low%" "%upp%"
>echo Random Number is: %r%& pause& goto:eof
>
>:_random
> echo>%2 randomize:wscript.echo int^(^(%4-%3+1^)*rnd+%3^)
> (for /f %%r in ('%~$path:1 %2')do set r=%%r)& del %2
...

OP wants shuffled numbers from 1 to 296, not a single integer from
within that range. If a single integer were all that's desired, the
OP's

set /a x=%random% %% 296 + 1

would probably suffice (though it's not uniform since 32768 isn't
divisible by 296). If it should be uniform, then

:loop
set /a x=%random%
if %x% gtr 32559 goto :loop
set /a x=x %% 296 + 1

If VBScript's Rnd were a high quality pseudorandom number generator,
then there might be some reason to use it. However, for the OP's task
of shuffling integers in a range, CMD's %RANDOM% is more than
sufficient. There are things VBScript can do that CMD and a few bundled
console utilities can't, but this isn't one of them.

b.ped...@get2net.dk

unread,
Feb 9, 2006, 2:30:12 AM2/9/06
to
Yes, I agree.
I just saw the headline: Printing random numbers,
and thought there wouldn't be any replys in VBS.

Benny,
PS. I like VBS :-)

Harlan Grove skrev:

Harlan Grove

unread,
Feb 9, 2006, 2:44:22 AM2/9/06
to
b.ped...@get2net.dk wrote...
...

>PS. I like VBS :-)
...

Have you tried microsoft.public.scripting.vbscript ?

b.ped...@get2net.dk

unread,
Feb 9, 2006, 3:47:02 AM2/9/06
to
Yes, but not recently. I will now concentrate on
nt batch (I want to improve my NT batch knowledge).

I know something about DOS in Win9X. Hmm, I remenber the step up from
version 6.22, that was hard in the beginning. Now when I do a step
forward from DOS in 9X til NT, it's the same hard.
but after writing about 5 batch files in NT, its now easy. But I probly
got much to learn.

Benny


Harlan Grove skrev:

Timo Salmi

unread,
Feb 9, 2006, 7:52:27 AM2/9/06
to
RazTK wrote:

> I tried to write a batch file that prints random numbers (from 1 to 296
> for example) and I tried to make it so it won't print a number that has
> already been shown, this is what I got:

> Do you have a better way to do this?

That can be called the shuffle problem (as for shuffle a deck of
cards). One algorithm is covered e.g. in
169462 Oct 27 2004 ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip
tsfaqp.zip Common Turbo Pascal Questions and Timo's answers

As for random numbers in scripts
87} How can I create a four-digit random string?
150924 Jan 11 2006 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html

RazTK

unread,
Feb 9, 2006, 8:05:57 AM2/9/06
to
Thank you all for your replies.
Timo, printing a four-digit random number is not my problem, thanks
anyway ;-)
I think Harlan gave me the best way to do my task.

Timo Salmi

unread,
Feb 9, 2006, 8:42:09 AM2/9/06
to
RazTK wrote:
> Timo, printing a four-digit random number is not my problem, thanks
> anyway ;-)

Your problem is the shuffle problem. Getting a random number is part
of the task. It is not overly difficult to get a three digit random
number in a specified range if one starts from how to get a
four-digit one.

> I think Harlan gave me the best way to do my task.

Excellent! (BTW note, the established programming methods for
the shuffle do not have the slowdown phenomenon.)

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland

Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip

Herbert Kleebauer

unread,
Feb 9, 2006, 8:45:11 AM2/9/06
to
RazTK wrote:
>
> I tried to write a batch file that prints random numbers (from 1 to 296
> for example) and I tried to make it so it won't print a number that has
> already been shown, this is what I got:

@echo off
setlocal
for /l %%i in (1,1,296) do set rand[%%i]=%%i
for /l %%i in (296,-1,1) do call :sub %%i
goto :eof

:sub
set /a x=%random% %% %1% + 1
call echo %%rand[%x%]%%
call set rand[%%x%%]=%%rand[%1]%%

RazTK

unread,
Feb 9, 2006, 9:07:56 AM2/9/06
to
Amazing. 0_0'
It will take me a while to understand how it works first.
Thank you.

RazTK

unread,
Feb 9, 2006, 2:03:35 PM2/9/06
to
Herbert, for some reason, your code doesn't work well when you try to
do it from 4 to 5 or from 3 to 4.

Harlan Grove

unread,
Feb 9, 2006, 2:14:13 PM2/9/06
to
Herbert Kleebauer wrote...
...

>@echo off
>setlocal
>for /l %%i in (1,1,296) do set rand[%%i]=%%i
>for /l %%i in (296,-1,1) do call :sub %%i

Usually the second loop ends at 2 since there's no point in swapping
a[1] with itself.

>goto :eof
>
>:sub
>set /a x=%random% %% %1% + 1
>call echo %%rand[%x%]%%
>call set rand[%%x%%]=%%rand[%1]%%

This is the textbook shuffling algorithm, and in languages with
integer-indexed arrays it's most efficient. However, CMD lacks arrays,
so each pseudo array element is a separate variable, and dereferencing
each one involves a linear search through the environment table, which
makes the CMD implementation O(N**2) rather than O(N) when using
indexed arrays. For only 296 entries, no big deal. For, say, 5000
entries, it's much slower than approaches using the sort command, which
is O(N log(N)).

RazTK

unread,
Feb 9, 2006, 3:01:27 PM2/9/06
to
And the code is not so good.
If you set it to 4 to 5 for example, it's broken since the file is
trying to get a random number from 1 to 4/5.

Timo Salmi

unread,
Feb 9, 2006, 3:42:52 PM2/9/06
to
RazTK <raz...@gmail.com> wrote:
> And the code is not so good.

Simple. Write a better one.

RazTK

unread,
Feb 9, 2006, 3:54:18 PM2/9/06
to
Well, I think the best and the most stable code is the one from Harlan.

PS. Don't tell me what to do.

Harlan Grove

unread,
Feb 9, 2006, 4:03:42 PM2/9/06
to
RazTK wrote...

>And the code is not so good.
>If you set it to 4 to 5 for example, it's broken since the file is
>trying to get a random number from 1 to 4/5.

To be fair, the code was specific to 1-based pseudo arrays. If you want
to use other bases, e.g., 4, then it's up to you to modify the code. In
this case,

set /a x=%random% %% (%1 - 4 + 1) + 4

or simplify to

set /a x=%random% %% (%1 - 3) + 4

Timo Salmi

unread,
Feb 9, 2006, 4:03:30 PM2/9/06
to
RazTK <raz...@gmail.com> wrote:
> PS. Don't tell me what to do.

I note that you and I are not seeing eye to eye. I happens. Best to
avoid each other from now on. Oh sorry, I shouldn't be telling you
what to do. So, you'll do whatever you decide, since you don't like
getting advice or answers from me.

Not to worry. I'll do the avoiding from now on.

Herbert Kleebauer

unread,
Feb 9, 2006, 4:09:07 PM2/9/06
to
RazTK wrote:
>
> Herbert, for some reason, your code doesn't work well when you try to
> do it from 4 to 5 or from 3 to 4.

I don't know what you mean. You wanted random numbers from 1 to 296.
If you want random numbers from 1 to 4, replace 296 by 4. If you want
random numbers starting by min (>=1) till max (>min) use:

@echo off
setlocal
set min=4
set max=5
for /l %%i in (%min%,1,%max%) do set rand[%%i]=%%i
for /l %%i in (%max%,-1,%min%) do call :sub %%i
goto :eof

:sub
set /a x=%1-min+1
set /a x=%random% %% x + min

Herbert Kleebauer

unread,
Feb 9, 2006, 4:10:06 PM2/9/06
to
Harlan Grove wrote:
> Herbert Kleebauer wrote...
> ...
> >@echo off
> >setlocal
> >for /l %%i in (1,1,296) do set rand[%%i]=%%i
> >for /l %%i in (296,-1,1) do call :sub %%i
>
> Usually the second loop ends at 2 since there's no point in swapping
> a[1] with itself.

Then only 295 and not 296 numbers are echoed.

Harlan Grove

unread,
Feb 9, 2006, 7:02:51 PM2/9/06
to
Herbert Kleebauer wrote...

Fair point. So add the statement

echo %rand[1]%

just after the second for loop. You don't need to call the subroutine
to try swapping rand[1] with itself. For that matter, there's probably
little need to call it when the iteration variable is less than 5. That
would require adding a third for loop like

for /L %%i in (5,-1,1) do call echo %%rand[%%i]%%

just before the goto :eof line.

Timo Salmi

unread,
Feb 10, 2006, 4:07:30 PM2/10/06
to
Herbert Kleebauer wrote:
> for /l %%i in (1,1,296) do set rand[%%i]=%%i
> for /l %%i in (296,-1,1) do call :sub %%i
<etc>

Another take. Using VBS-aided scripting and the shuffle algoritm to
avoid any repeats:

@echo off & setlocal enableextensions enabledelayedexpansion

::
:: Set the number of random numbers to be shuffled
:: Typically 52 would be a deck of cards
set max_=52
::
:: Build a Visual Basic Script
set vbs_=%mytemp%\tmp$$$.vbs
findstr "'%skip%VBS" "%~f0" > %vbs_%
::
:: Run it with Microsoft Windows Script Host Version 5.6
set cmd_=%mytemp%\tmp$$$.cmd
cscript //nologo %vbs_% > %cmd_%
::
:: Call the command line script which the script host built
call %cmd_%
::
:: Display the results
for /l %%i in (1,1,%max_%) do echo rand[%%i] = !rand[%%i]!
::
:: Clean up
for %%f in ("%vbs_%" "%cmd_%") do if exist %%f del %%f
endlocal & goto :EOF
'
'.......................................................
'The Visual Basic Script
'
Dim maxItems, i, j, k, rand(1000) 'VBS
Set WshShell = WScript.CreateObject("WScript.shell") 'VBS
maxItems=WshShell.ExpandEnvironmentStrings("%max_%") 'VBS
Randomize 'VBS
For i = 1 to MaxItems 'VBS
rand(i) = i 'VBS
Next 'VBS
For i = 1 to MaxItems 'VBS
j = 1 + Int(MaxItems*rnd) 'VBS
k = rand(i) 'VBS
rand(i) = rand(j) 'VBS
rand(j) = k 'VBS
Next 'VBS
For i = 1 to MaxItems 'VBS
WScript.Echo "@set rand[" & i & "]=" & rand(i) 'VBS
Next 'VBS

The output would be e.g.
C:\_D\TEST>cmdfaq
rand[1] = 3
rand[2] = 6
:
rand[50] = 36
rand[51] = 26
rand[52] = 40

Dr John Stockton

unread,
Feb 11, 2006, 7:17:23 AM2/11/06
to
JRS: In article <43ed009a$0$25335$9b53...@news.fv.fi>, dated Fri, 10
Feb 2006 23:07:30 remote, seen in news:alt.msdos.batch.nt, Timo Salmi
<t...@uwasa.fi> posted :

>
>Another take. Using VBS-aided scripting and the shuffle algoritm to
>avoid any repeats:

For brevity and greater efficiency, allow me to suggest the algorithm
posted by Horst Kraemer and quoted at the end of Section 140 of the
invaluable Turbo Pascal FAQ cited in sig line 4 below. ISTM that its
first statement can be removed if the loop is changed to start at 1.


BTW, I suggest changing the Subject of that section to "Shuffling or
dealing a deck of cards".

The destination of the quoted link has moved from pascal.htm#Rand to
pas-rand.htm, and pas-time.htm#Delay in #67 is now pas-wait.htm#Delay.

--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME. ©
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/&c., FAQqy topics & links;
<URL:http://www.merlyn.demon.co.uk/clpb-faq.txt> RAH Prins : c.l.p.b mFAQ;
<URL:ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip> Timo Salmi's Turbo Pascal FAQ.

Timo Salmi

unread,
Feb 11, 2006, 3:09:32 PM2/11/06
to
Dr John Stockton wrote:

> Timo Salmi <t...@uwasa.fi> posted :
>> Another take. Using VBS-aided scripting and the shuffle algoritm
>> to avoid any repeats:

> For brevity and greater efficiency, allow me to suggest the
> algorithm posted by Horst Kraemer and quoted at the end of Section
> 140 of the invaluable Turbo Pascal FAQ cited in sig line 4 below.

Thanks John. I have added a link to your posting in the cmd FAQ
random item.

> BTW, I suggest changing the Subject of that section to "Shuffling
> or dealing a deck of cards".

Can't do. The subject lines in the pascal FAQ are limited in length.

> The destination of the quoted link has moved from pascal.htm#Rand
> to pas-rand.htm, and pas-time.htm#Delay in #67 is now
> pas-wait.htm#Delay.

Corrected. Even if it is unlikely that my Turbo Pascal FAQ will have
new versions.

In case anyone wonders what this has to do with scripting. Well, some
of the programming algorithms are easily portable as was the card
shuffling algorithm.

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland

RazTK

unread,
Feb 11, 2006, 8:00:39 PM2/11/06
to
How can I use the shuffle algorithm with steps?
If I want to generate a random number from 0 to 10 like this: 0, 2, 4,
6, 8, 10 (2 steps between each number)?

Harlan Grove

unread,
Feb 11, 2006, 8:28:12 PM2/11/06
to
"RazTK" <raz...@gmail.com> wrote...

>How can I use the shuffle algorithm with steps?
>If I want to generate a random number from 0 to 10 like this: 0, 2, 4,
>6, 8, 10 (2 steps between each number)?

If you had a random integer, r, drawn from 1 to 6, use it to generate a
random even integer between 0 and 10 as (r - 1) * 2.


Matt Williamson

unread,
Feb 14, 2006, 2:03:12 PM2/14/06
to

>"Timo Salmi" <t...@uwasa.fi> wrote in message
>news:43ed009a$0$25335$9b53...@news.fv.fi...

> Another take. Using VBS-aided scripting and the shuffle algoritm to
> avoid any repeats:
>
> :: Build a Visual Basic Script
> set vbs_=%mytemp%\tmp$$$.vbs
> findstr "'%skip%VBS" "%~f0" > %vbs_%

Where does '%skip% come from in that last line?

Thanks

Matt


Timo Salmi

unread,
Feb 14, 2006, 4:02:20 PM2/14/06
to
Matt Williamson wrote:
>>"Timo Salmi" <t...@uwasa.fi> wrote in message
>> :: Build a Visual Basic Script
>> set vbs_=%mytemp%\tmp$$$.vbs
>> findstr "'%skip%VBS" "%~f0" > %vbs_%

> Where does '%skip% come from in that last line?

Ah, you missed the essence of the trick. (It's empty. Of course.)

Matt Williamson

unread,
Feb 14, 2006, 4:23:26 PM2/14/06
to
Could you explain how it works? I found a couple other posts where you use
the same findstr "'%skip%" trick and in some %skip% is defined as nothing
and others it's not defined at all, which is the same so that fact is
insignificant. I still don't know what's going on behind the scenes.

Thanks

Matt


"Timo Salmi" <t...@uwasa.fi> wrote in message

news:43f24560$0$25333$9b53...@news.fv.fi...

foxidrive

unread,
Feb 14, 2006, 6:10:19 PM2/14/06
to
On Tue, 14 Feb 2006 16:23:26 -0500, Matt Williamson wrote:

> Could you explain how it works? I found a couple other posts where you use
> the same findstr "'%skip%" trick and in some %skip% is defined as nothing
> and others it's not defined at all, which is the same so that fact is
> insignificant. I still don't know what's going on behind the scenes.
>
> Thanks
>
> Matt
>
>
> "Timo Salmi" <t...@uwasa.fi> wrote in message
> news:43f24560$0$25333$9b53...@news.fv.fi...
>> Matt Williamson wrote:
>>>>"Timo Salmi" <t...@uwasa.fi> wrote in message :: Build a Visual Basic
>>>>Script
>>>> set vbs_=%mytemp%\tmp$$$.vbs
>>>> findstr "'%skip%VBS" "%~f0" > %vbs_%
>>
>>> Where does '%skip% come from in that last line?
>>
>> Ah, you missed the essence of the trick. (It's empty. Of course.)
>>

Not to steal Timo's thunder - it stops findstr from filtering that same
line into the output file, as it is not literally 'VBS.

0 new messages