2012-02-02 6 views
10

IFは2つの大きな数字を比較しようとすると間違った答えを出します。例えばWindowsバッチファイルIF障害 - 30000000000000はどのようにして40000000000になりますか?

、この単純なバッチファイル

@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 

を生成し、私はこれをどのように修正するのですか?

答えて

30

IF比較の両辺が厳密に10進数で構成されている場合、IFは両辺を数値として解釈します。これは、IFが10が9より大きいと正しく判断できるようにするものです。非数字の文字がある場合、IFは文字列の比較を行います。たとえば、 "10"は "9"より小さいので、引用符は数字ではなく、1のソートは9より小さい。

質問の比較が失敗するのは、CMD.EXEが2147483647より大きい数値を処理できないためです。 IFの奇妙なデザインは、2147483647より大きい数値を2147483647とみなします。

大規模な文字列比較を行う場合は、簡単です。条件の両側に1つ以上の非数字文字を追加するだけです。次のスクリプト -

@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 less than "40000000000" 

を生成するが、ほとんどの場合、これが望まれているものではありません。

数値比較を行う場合は、プロセスがもう少し複雑になります。数値を、数値として適切にソートする文字列に変換する必要があります。これは、両方の数値ストリングを同じ幅にする方法で、数字ストリングの前にゼロを付けることによって達成されます。最も簡単な解決策は、サポートする必要のある最大桁数を決定することです。この例では15としましょう。したがって、各値の先頭に15桁のゼロを付け、部分文字列操作を使用して右端の15文字のみを保持します。また、以前と同じように両桁に非数字を追加する必要があります。もう一度引用符がうまく機能します。

このスクリプト -

@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 

注意がゼロと同じようにうまく動作します。

後で次を使用していつでも先頭のゼロを削除(または先頭のスペースを削除するために適応させる)

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

通常、我々は、バッチファイルで大量に対処していないことができます。しかし、ハードディスク上の空き領域を見ると、簡単に切り取ることができます。テラバイトのディスクドライブは、現在比較的安価です。これは私が最初に大量の比較をしたところですhttps://stackoverflow.com/a/9099542/1012053

これは私の例では15桁をサポートしていたので、これはほぼ999テラバイトに相当します。それよりも大きなディスクドライブを扱うには、しばらく時間がかかると私は思います。 (しかし誰が知っている!)

EDIT - IFが数字を解析する方法の私の説明は意図的に過度に単純化しています。 IFは実際には負の数だけでなく、16進表記と8進表記もサポートしています。より完全な説明はRules for how CMD.EXE parses numbersを参照してください。

+0

これは本当に素晴らしかったです。ありがとう – Lupocci

+0

数値の比較は、両側が厳密に10進数ではなく整形式である場合に行われます。たとえば、-1または0xabcまたは+43は数値的に比較されますが、09は無効です(09は無効な8進数です)。 –

+1

@PaulH - 絶対に正しいですが、大量のQ&Aの中心点から逸脱したくありませんでした。大規模な数字が最大許容整数として扱われるという点を圧倒することのない簡潔な説明を思いついた。詳細は、[CMD.EXEが数値をどのように解析するかについての規則]でご覧になれます。(http://www.dostips.com/forum/viewtopic.php?t=3758) – dbenham