Windows 批处理文件如果失败 - 30000000000000 如何等于 40000000000? [英] Windows batch file IF failure - How can 30000000000000 equal 40000000000?

查看:18
本文介绍了Windows 批处理文件如果失败 - 30000000000000 如何等于 40000000000?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试比较 2 个大数时,IF 给出了错误的答案.

IF gives the wrong answer when I try to compare 2 large numbers.

例如这个简单的批处理文件

For example, this simple batch file

@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%

生产

30000000000000 is equal to 40000000000

这是怎么回事,我该如何解决?

What is going on, and how do I fix this?

推荐答案

如果 IF 比较的两边都严格由十进制数字组成,那么 IF 会将两边都解释为数字.这就是使 IF 能够正确确定 10 大于 9 的原因.如果您有任何非数字字符,则 IF 会进行字符串比较.例如,10"小于9",因为引号不是数字,1 排序小于 9.

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.

问题中的比较失败的原因是因为 CMD.EXE 无法处理大于 2147483647 的数字.IF 中的一个奇怪的设计怪癖将任何大于 2147483647 的数字视为等于 2147483647.

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.

如果你想做大数的字符串比较,那么解决方法很简单.您只需要在条件的两侧添加 1 个或多个非数字字符.以下脚本 -

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.

如果要进行数字比较,则过程会更复杂一些.您需要将数字转换为可以作为数字正确排序的字符串.这是通过在数字字符串前面加上零以使得两个数字字符串具有相同宽度的方式来实现的.最简单的解决方案是确定您需要支持的最大位数 - 在此示例中假设为 15.因此,您用 15 个零作为每个值的前缀,然后使用子字符串操作仅保留最右边的 15 个字符.您还需要像以前一样在两边添加一个非数字 - 再次引用效果很好.

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.

这个脚本-

@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

产生 -

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"

通常我们不处理批处理文件中的大量数据.但是如果我们查看硬盘上的可用空间,它们很容易出现.TB 磁盘驱动器现在相对便宜.这是我第一次在 https://stackoverflow.com/a/9099542/1012053

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

在我的示例中,我选择支持 15 位数字,因为这相当于近 999 TB.我想我们还需要一段时间才能处理比这更大的磁盘驱动器.(但谁知道呢!)

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 - 我对 IF 如何解析数字的描述故意过于简单化.IF 实际上支持负数,以及十六进制和八进制表示法.请参阅CMD.EXE 如何解析数字的规则以获得更详尽的解释.

这篇关于Windows 批处理文件如果失败 - 30000000000000 如何等于 40000000000?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆