Windows batch file IF failure – How can 30000000000000 equal 40000000000?

If both sides of an IF comparison are composed strictly of decimal digits, then IF will interpret both sides as numbers. This is what enables IF to correctly determine that 10 is greater than 9. If you have any non digit characters, then IF does a string comparison. For example, “10” is less than “9” because the quotes are not digits, and 1 sorts lower than 9.

The reason the comparison in the question fails is because CMD.EXE cannot process numbers larger than 2147483647. An odd design quirk in IF treats any number larger than 2147483647 as being equal to 2147483647.

If you want to do a string comparison of large numbers, then the solution is easy. You just need to add 1 or more non digit characters to both sides of the condition. The following script –

@echo off
setlocal
set n1=30000000000000
set n2=40000000000
if "%n1%" gtr "%n2%" echo "%n1%" is greater than "%n2%"
if "%n1%" lss "%n2%" echo "%n1%" is less than "%n2%"
if "%n1%" equ "%n2%" echo "%n1%" is equal to "%n2%"

produces the correct string comparison result

"30000000000000" is less than "40000000000"

But in most cases, this is not what is wanted.

If you want to do a numeric comparison, then the process is a bit more involved. You need to convert the number into a string that will sort properly as a number. This is accomplished by prefixing the numeric string with zeros in a way that makes both numeric strings the same width. The simplest solution is to determine the maximum number of digits you need to support – let’s say 15 for this example. So you prefix each value with 15 zeros, and then preserve only the right-most 15 characters by using a substring operation. You also need to add a non-digit to both sides as before – again quotes work well.

This script –

@echo off
setlocal
set n1=30000000000000
set n2=40000000000
call :padNum n1
call :padNum n2
if "%n1%" gtr "%n2%" echo %n1% is greater than %n2%
if "%n1%" lss "%n2%" echo %n1% is less than %n2%
if "%n1%" equ "%n2%" echo %n1% is equal to %n2%
exit /b

:padNum
setlocal enableDelayedExpansion
set "n=000000000000000!%~1!"
set "n=!n:~-15!"
endlocal & set "%~1=%n%"
exit /b

produces –

030000000000000 is greater than 000040000000000

Note that left prefixing with spaces works just as well as zeros.

You can later remove the leading zeros whenever you want using the following (or adapt to remove leading spaces)

for /f "tokens=* delims=0" %%A in ("%n1%") do set "n1=%%A"
if not defined n1 set "n1=0"

Normally we don’t deal with large numbers in batch files. But they can easily crop up if we look at free space on a hard disk. Terabyte disk drives are now relatively inexpensive. This is how I first ran into comparison of large numbers at https://stackoverflow.com/a/9099542/1012053

I chose to support 15 digits in my example because that equates to almost 999 terabytes. I imagine it will be a while before we have to deal with disk drives larger than that. (But who knows!)

EDIT – My description of how IF parses numbers is intentionally overly simplistic. IF actually supports negative numbers, as well as hex and octal notation. See Rules for how CMD.EXE parses numbers for a much more thorough explanation.

Leave a Comment