Calculations with large numbers

Hi,

I've been trying to write a batch file to perform a number of calculations using some fairly large numbers, however whenever I try I get the following message, for example:

C:\> set /a total=11787702272+1
Invalid number.  Numbers are limited to 32-bits of precision.

Seems to happen whenever the number is more than 10 digits in length. I'm trying to use numbers that are 11 or 12 digits in length. I assume 10 is the limit in the command prompt/dos. Is there any way around it? I've looked for other command line utilities that do the same thing as 'set /a' but couldn't find anything at all. Any ideas?

Any help appreciated.

Thanks
LVL 3
simonprrAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

GuruGaryCommented:
The command prompt SET command uses 32 bit integers.  So you can use numbers up to 4 GB or 4,294,967,295.  If you want something bigger than that, you will probably have to use a 3rd party program ... unless you want to split the number up, do math on the parts, and then combine the parts as text.

What exactly are you trying to do?  Maybe we can help come up with a better solution?
simonprrAuthor Commented:
The script I'm creating is to output the % disk space usage on some servers. I know there is lots of programs which do this, but I want a script to run everyday and output it to a text file or something so management can look at it and so that it's completely automated. I also wanted to be able to do it in a batch file so I can fix/amend etc when necessary.

I was going to do it like this:

Use dir /-c to get the free disk space
Use diruse to get the used space
Then add them together
Then divide used space by total space and times by 100 = 25%

I know by default dir outputs the free space like you mentioned, and diruse can output it in bytes/KB/MB, but couldn't figure out how to do the calculations with the comers in it!

Hope this helps!

Thanks
simonprrAuthor Commented:
Oops, ignore that 25% bit, should just be the % used.
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

SteveGTRCommented:
This doesn't solve your problem, but this can get the information you want a little faster:

@echo off

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~1

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk get caption, size, freespace 2>NUL >_temp.txt

for /f "tokens=2,3" %%a in ('type _temp.txt 2^>NUL ^| findstr /i "%drv%"') do set size=%%a&set free=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

echo %drv% size=%size% free=%free%

Good Luck,
Steve
Steve KnightIT ConsultancyCommented:
I haven't got time to play with this at the moment but I was toying with the idea of leaving in the comma seperators then you can get the free space in Mb (near enough) by trimming off the last two sections which would make the maths smaller.  Trouble with what I have here is it would misreport if space dropped below 1Gb ....

for /f "tokens=3,4 delims=, " %a in ('dir /c ^| find /i "dir(s)"') do echo %a%b

GuruGaryCommented:
You can just chop off the last 3 digits (or more) of the numbers for total space and free space and do your math on those  numbers.  The percentage should still work out to be the same.

DIRUSE is not the quickest way to figure out the total disk space, but SteveGTR's solution looks good.  Or you can also try the FSUTIL command (fsinfo sub-command).  You can use SET command and the %~ notation to work with a portion of the number to calculate your percentages without using a number that is too big.
simonprrAuthor Commented:
Nice. Thanks Steve. Certainly gets the disk usage information quickly. I think "do set size=%%a&set free=%%b" should be "do set free=%%a&set size=%%b" though, as it's outputting them the wrong way round for me.

I have tried removing the last 3 digits of the sizes and then working out the percentages, but it's not coming out right because dos can't handle decimals (I think) although I managed to do this before. It keeps outputting as 0 or 1. I can't remember the way round this - any ideas?

Thanks for the help so far everyone!
Danny ChildIT ManagerCommented:
we used to use Hyena to get disk space stats, and it could either produce reports in HTML or CSV for Excel.  I think it had some scripting tools as well, but we used to point it at some servers, get some coffee, and then look at the pretty stats that it had recovered.  Mind you, it was about 3 years ago.  Good tool though!

http://www.systemtools.com/hyena/

Dos is fun, but why re-invent this particular wheel?
SteveGTRCommented:
I'm not a vbs script wizard, but it could help out in this case. Try this:

@echo off

setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~1

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt

for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

>temp.vbs echo Wscript.Echo wscript.arguments(0) / wscript.arguments(1) * 100

for /f "delims=" %%a in ('cscript //NOLOGO _temp.vbs %free% %size% 2^>NUL') do set percent=%%a

echo Percent free on %drv% is %percent%

del _temp.vbs 2>NUL
GuruGaryCommented:
Or to work around the calculations for your batch file, you can do something like:

set /a percentage=%free:~,-3%/%size:~-5

That should give you the whole number percentage of free disk space
GuruGaryCommented:
Reading my post, it looks like I missed a comma.  Sorry.  Should be:

set /a percentage=%free:~,-3%/%size:~,-5%
SteveGTRCommented:
That works very well :)
Steve KnightIT ConsultancyCommented:
And would you believe it that syntax is in the help for set /? and I'd never seen it before, right at the top of a new page :-)  Cool.

Steve
simonprrAuthor Commented:
Well, you have all given me a lot to think about!

DanCh99: I did consider a separate application like hyena but couldn't justify the cost given that we already have other applications that have similar features. I also like scripts cause I can adapt them exactly how I want (usually). Just wish I knew VB or something :)

GuruGary: Works well!

Steve: That script is very interesting... one thing though, if I'm reading it right, I should be able to:
C:\> diskspace server c
But it comes back with "Could not get drive information for server"  Server does exist.

dragon-it: I can't see it in set /? I must be blind.... :)


The problem still exists in a way though - doing large calculations, which for this I have a way round, but I will need to convert the bytes to GBs otherwise the % used can be meaningless. GuruGary: Is there a way to do this like the way you have worked out the percentage?
SteveGTRCommented:
Another bug in my code :(

You can use the batch processing like this (if you named it GetPercentFree.bat):

GetPercentFree c
GetPercentFree yourserver c

@echo off

setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt

for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

>_temp.vbs echo Wscript.Echo wscript.arguments(0) / wscript.arguments(1) * 100

for /f "delims=" %%a in ('cscript //NOLOGO _temp.vbs %free% %size% 2^>NUL') do set percent=%%a

echo Percent free on %drv% is %percent%

del _temp.vbs 2>NUL
GuruGaryCommented:
This is 95% SteveGTR's code ... but I think this is what you are looking for without using VBS code:

@echo off

setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt

for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

set /a percentage=%free:~,-3%/%size:~,-5%

echo Drive %drv% has %free:~,-9% GB free space which is %percentage%%%



You could have some more precision (like 12.12 GB and 12.12%) if you want to do a couple more math calculations.  I don't know how accurate this needs to be.
simonprrAuthor Commented:
Works well guys! Thanks. Good team work :)

The percentage is fine, but I think the free space needs to be a bit more precise. For example:

C:\>diskspace server c
Drive c: has 29 GB free space which is 48%

However Windows tells me I have 27.6Gb free.

I think I've asked this before... been trying to find it. This is what I have so far, seems closer, but not quite right:

C:\>diskspace server c
Drive c: has 29 GB free space which is 48% free
28.3

============================================
@echo off

setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt

for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

set /a percentage=%free:~,-3%/%size:~,-5%

echo Drive %drv% has %free:~,-9% GB free space which is %percentage%%% free

set /a tenthmb = (1024 * 1024) / 10
set /a mbdecimal = %free:~,-3%/%tenthmb%
if %mbdecimal% LSS 10 set mbdecimal=0%mbdecimal%
set mbdecimal=%mbdecimal:~0,-1%.%mbdecimal:~-1%

echo %mbdecimal%
============================================

Is this because we have had to shorten the %free% variable?
SteveGTRCommented:
If you look at the bytes to the left of the GB on the Drive's property sheet you'll see that number of bytes starts with 29.

A GB is equal to 1,073,741,824 bytes not 1,000,000,000. On my machine there are 90,032,271,360 bytes free and it Windows Explorer reports there are 83.8 GB free.

This is 90,032,271,360 / 1,073,741,824 = 83.849086761474609375

If you want a more precise number then the scripting option will do whatever you want...
GuruGaryCommented:
I think Steve is right.  I think it is because the calculation we are using is the "billions of bytes" calculation.  The number from Windows is probably true gibabytes.  Using Steve's number, we can still do math in the batch file.  Round off the GB calculation to thousands and we can use this for the last 2 lines (which will give us more precision, and should match the Windows answer):

set /a freeGB=%free:~,-3%/1074
echo Drive %drv% has %freeGB:~,-3%.%freeGB:~-3,2% GB free space which is %percentage%%%


So the full batch file would be (still 95% SteveGTR's code):
@echo off

setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt

for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

set /a percentage=%free:~,-3%/%size:~,-5%
set /a freeGB=%free:~,-3%/1074

echo Drive %drv% has %freeGB:~,-3%.%freeGB:~-3,2% GB free space which is %percentage%%%
simonprrAuthor Commented:
Great. Thats it!

I have been thoroughly testing this the last couple of days and haven't encountered any issues yet. I assume this way of calculating the sizes and percentage will work with any size drive up to 999GB (1TB)?

I've added the used GB myself using the same formula and think it is working right...although I'm not getting the precise value, but I've done it the same way as you have:

======
@echo off
cls
echo Please wait...
setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt
cls
for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

set /a used=%size:~,-3%-%free:~,-3%

set /a percentage=%free:~,-3%/%size:~,-5%

set /a freeGB=%free:~,-3%/1074
set /a usedGB=%used:~,-3%/1074
set /a sizeGB=%size:~,-3%/1074

echo Drive %drv% has %freeGB:~,-3%.%freeGB:~-3,2% GB free space which is %percentage%%% free
echo Drive %drv% is %sizeGB:~,-3%.%sizeGB:~-3,2% GB in size
echo Drive %drv% has %usedGB% GB used space
======

I don't understand why we do -3 for the free value and -5 for the size value here:
set /a percentage=%free:~,-3%/%size:~,-5%
I would have thought it would make it un-even?! Sorry I'm a bit confused!

Thanks again, almost there :)
GuruGaryCommented:
The reason for the difference in the -3 and the -5 is to save a calculation.  What we really want is:
((%free:~,-3%) / (%size:~,-3%) / 100)
to convert free to a percentage.  But since we are dropping the last 6 digits of that number anyway, the 3rd through the 5th digits are insignificant, and instead of doing an extra calculation we can basically "move the decimal over 2 places" in one of our numbers to simulate the /100.

Your calculation for the used space was right, but you don't need the -3 since you got that calculation from 2 numbers that already had the -3.  So you just need to change 2 lines:
set /a usedGB=%used%/1074 (take away the -3)
and:
echo Drive %drv% has %usedGB:~,-3%.%usedGB:~-3,2% GB used space (use the -3 here to give your precision)
GuruGaryCommented:
So your script (which is mostly SteveGTR's code) with the 2 changes would be:

@echo off
cls
echo Please wait...
setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt
cls
for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

set /a used=%size:~,-3%-%free:~,-3%

set /a percentage=%free:~,-3%/%size:~,-5%

set /a freeGB=%free:~,-3%/1074
set /a usedGB=%used:~,-3%/1074
set /a sizeGB=%size:~,-3%/1074

echo Drive %drv% has %freeGB:~,-3%.%freeGB:~-3,2% GB free space which is %percentage%%% free
echo Drive %drv% is %sizeGB:~,-3%.%sizeGB:~-3,2% GB in size
echo Drive %drv% has %usedGB% GB used space
GuruGaryCommented:
Oops.  I just realized that is the original script without the 2 changes (sorry).  How about this:

@echo off
cls
echo Please wait...
setlocal

if "%~1"=="" echo usage %0: [[computer drive], drive]&goto :EOF

if "%~2"=="" set compName=.&set drv=%~1
if not "%~2"=="" set compName=%~1&set drv=%~2

if "%drv:~1%"=="" set drv=%drv%:

set size=

wmic /Failfast:on /node:%compName% logicaldisk where caption='%drv%' get size, freespace 2>NUL >_temp.txt
cls
for /f "skip=1 tokens=1,2" %%a in ('type _temp.txt 2^>NUL') do set free=%%a&set size=%%b

del _temp.txt 2>NUL

if "%size%"=="" echo Could not get drive information for %drv%&goto :EOF

set /a used=%size:~,-3%-%free:~,-3%

set /a percentage=%free:~,-3%/%size:~,-5%

set /a freeGB=%free:~,-3%/1074
set /a usedGB=%used%/1074
set /a sizeGB=%size:~,-3%/1074

echo Drive %drv% has %freeGB:~,-3%.%freeGB:~-3,2% GB free space which is %percentage%%% free
echo Drive %drv% is %sizeGB:~,-3%.%sizeGB:~-3,2% GB in size
echo Drive %drv% has %usedGB:~,-3%.%usedGB:~-3,2% GB used space

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
simonprrAuthor Commented:
Brilliant!

Thanks GuruGary for the help and amendments to Steve's code to get exactly what I wanted and BIG thanks to Steve for the original code too!

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft DOS

From novice to tech pro — start learning today.