【bat】バッチファイルで計算する方法完全ガイド|set /a・小数点・合計・平均・時間計測・進数変換まで徹底解説

バッチファイルで計算が必要な場面は思いの外多いものです。ファイル数のカウント、処理時間の計測、ファイルサイズの合計、日付の差分計算……。Windowsバッチには set /a という整数演算コマンドがあり、PowerShell と組み合わせれば小数点計算・統計・16進変換まで対応できます。この記事では「実際の現場で使う計算パターン」に絞って体系的に解説します。

この記事でわかること

  • set /a の演算子一覧と複合代入・インクリメント
  • 整数演算の制限(32bit・小数点なし)と回避策
  • PowerShell と連携した小数点計算・数学関数
  • ループ内での合計・平均・最大値・最小値の求め方
  • 処理時間の計測方法(%TIME% / Measure-Command)
  • ファイルサイズの合計を計算する方法
  • 16進数・8進数・2進数の変換
  • 実践例3本(ログ行数レポート・処理時間計測・ファイルサイズ集計)
スポンサーリンク

1. set /a の基本:整数演算の全演算子

バッチファイルの計算は set /a 変数=式 で行います。結果は必ず32bit 符号付き整数(-2,147,483,648 〜 2,147,483,647)になります。

演算子 意味 結果
+ 加算 set /a r=10+3 r=13
- 減算 set /a r=10-3 r=7
* 乗算 set /a r=10*3 r=30
/ 整数除算(切り捨て) set /a r=10/3 r=3
%% 剰余(余り) set /a r=10%%3 r=1
+= / -= 複合代入(加算/減算) set /a r+=5 現在値に5加算
*= / /= 複合代入(乗算/除算) set /a r*=2 現在値を2倍
%%= 複合代入(剰余) set /a r%%=3 現在値の3の余り
& / | ビットAND / ビットOR set /a r=12&10 r=8
^ ビットXOR set /a r=12^10 r=6
~ ビット反転(NOT) set /a r=~0 r=-1
<< / >> ビット左シフト / 右シフト set /a r=1<<4 r=16

1-1. 基本的な四則演算

@echo off
setlocal

set /a A=100
set /a B=7

set /a SUM=%A%+%B%
set /a DIFF=%A%-%B%
set /a PROD=%A%*%B%
set /a QUOT=%A%/%B%
set /a REM=%A%%%B%

echo %A% + %B% = %SUM%
echo %A% - %B% = %DIFF%
echo %A% * %B% = %PROD%
echo %A% / %B% = %QUOT%  (小数部分は切り捨て)
echo %A% %% %B% = %REM%  (余り)

1-2. 複合代入とインクリメント

@echo off
setlocal

set /a COUNT=0

:: インクリメント(1ずつ増やす)
set /a COUNT+=1
set /a COUNT+=1
echo COUNT = %COUNT%

:: 2倍にする
set /a COUNT*=2
echo COUNT*2 = %COUNT%

:: 3の倍数か判定(剰余が0なら倍数)
set /a MOD=%COUNT%%%3
if %MOD% equ 0 (
    echo %COUNT% は 3 の倍数です
) else (
    echo %COUNT% は 3 の倍数ではありません
)
バッチファイルでの %% の書き方
剰余演算子 % はバッチファイル内では %% と書く必要があります。set /a r=10%%3 のように2つ重ねてください。コマンドプロンプトで直接実行する場合は % 1つで動作します。

set /a の演算子・優先順位・ビット演算の詳細は SET /A で数値計算する方法完全解説 も参照してください。

2. 整数演算の制限と回避策

set /a は整数のみ・小数点は扱えない
set /a r=10/3 の結果は 3 です(小数部分は切り捨て)。set /a r=1.5+2.5 はエラーになります。小数点計算が必要な場合は PowerShell を使ってください。
状況 set /a の挙動 対策
小数点計算(1.5+2.3) エラー PowerShell を使う
大きな数(21億超) オーバーフロー(負の値になる) 値を分割・PowerShell を使う
除算の小数部分 切り捨て(10/3=3) 擬似小数点(×10倍法)または PowerShell
負の数 正常に扱える 対策不要
16進数リテラル 0x1F 形式で使用可 そのまま使える

2-1. 擬似小数点:×N倍法(set /a 限定)

小数第1位まで計算したい場合、値を10倍して計算し、表示時に割り戻す方法があります。

@echo off
setlocal

:: 例: 消費税率 10% の計算(1円以下は切り捨て)
set /a PRICE=1980

:: ×10倍して税込み価格を計算(整数演算で1円単位)
set /a TAX_PRICE=%PRICE%*11/10
echo 税込み価格: %TAX_PRICE% 円

:: 小数第1位まで求めたい場合は ×10倍して計算
set /a PRICE_X10=%PRICE%*10
set /a RATIO_INT=%PRICE_X10%*11/100
set /a INT_PART=%RATIO_INT%/10
set /a DEC_PART=%RATIO_INT%%%10
echo 税込み(小数第1位): %INT_PART%.%DEC_PART% 円

2-2. オーバーフロー対策

@echo off
setlocal

:: 32bit 上限は 2,147,483,647
:: ファイルサイズ(byte)が 2GB を超えると set /a でオーバーフローする

:: 対策1: KB・MB 単位に変換してから計算する
set /a SIZE_BYTE=1500000000
set /a SIZE_MB=%SIZE_BYTE%/1048576
echo サイズ: %SIZE_MB% MB

:: 対策2: 2GB 超えるものは PowerShell で計算する(後述)

3. PowerShell と連携した小数点・高精度計算

powershell -Command を呼び出すことで、バッチファイルから浮動小数点演算や数学関数を利用できます。

3-1. 基本的な小数点計算

@echo off

:: 小数点計算
powershell -Command "Write-Host (1.5 + 2.3)"

:: 変数に格納して後続処理に使う
for /f %%R in ('powershell -Command "Write-Host ([math]::Round(1.5 + 2.3, 2))"') do set RESULT=%%R
echo 計算結果: %RESULT%

:: 割り算(小数点以下4桁まで)
for /f %%R in ('powershell -Command "Write-Host ([math]::Round(10/3, 4))"') do set DIV=%%R
echo 10 / 3 = %DIV%

3-2. 数学関数(平方根・べき乗・三角関数)

@echo off

:: 平方根
for /f %%R in ('powershell -Command "Write-Host ([math]::Sqrt(144))"') do set SQRT=%%R
echo √144 = %SQRT%

:: べき乗(2^10)
for /f %%R in ('powershell -Command "Write-Host ([math]::Pow(2, 10))"') do set POW=%%R
echo 2^10 = %POW%

:: 絶対値
for /f %%R in ('powershell -Command "Write-Host ([math]::Abs(-42))"') do set ABS=%%R
echo |-42| = %ABS%

:: 対数(log10)
for /f %%R in ('powershell -Command "Write-Host ([math]::Round([math]::Log10(1000), 4))"') do set LOG=%%R
echo log10(1000) = %LOG%

3-3. 変数を PowerShell に渡して計算する

@echo off
setlocal

set /p PRICE=価格を入力: 
set /p QTY=数量を入力: 

:: バッチ変数を PowerShell の式に埋め込む
for /f %%R in ('powershell -Command "Write-Host ([math]::Round(%PRICE% * %QTY% * 1.1, 0))"') do set TOTAL=%%R
echo 税込み合計: %TOTAL% 円
PowerShell 呼び出しはバッチ単独より遅い
PowerShell の起動には約0.5〜2秒かかります。ループ内で毎回 powershell -Command を呼ぶとスクリプト全体が極端に遅くなります。ループ内計算は set /a で行い、最後の集計だけ PowerShell に渡すように設計してください。

4. ループ内の統計計算(合計・平均・最大値・最小値)

4-1. 合計・件数・平均を求める

@echo off
setlocal enabledelayedexpansion

:: ファイルの行数と数値の合計を計算する例
set TOTAL=0
set COUNT=0

for /f "usebackq delims=" %%L in ("numbers.txt") do (
    set /a TOTAL+=%%L
    set /a COUNT+=1
)

echo 件数: %COUNT%
echo 合計: %TOTAL%

:: 平均(整数部分のみ)
if %COUNT% gtr 0 (
    set /a AVG=%TOTAL%/%COUNT%
    echo 平均: %AVG%
) else (
    echo データがありません
)

4-2. 最大値・最小値を求める

@echo off
setlocal enabledelayedexpansion

set MAX=-2147483648
set MIN=2147483647
set COUNT=0

for /f "usebackq delims=" %%N in ("numbers.txt") do (
    set /a COUNT+=1

    :: 最大値の更新
    if %%N gtr !MAX! set /a MAX=%%N

    :: 最小値の更新
    if %%N lss !MIN! set /a MIN=%%N
)

echo 件数: %COUNT%
echo 最大: %MAX%
echo 最小: %MIN%
echo 範囲: 
set /a RANGE=%MAX%-%MIN%
echo %MAX% - %MIN% = %RANGE%

4-3. 数値入力のバリデーション(数値かどうかチェック)

@echo off
setlocal

:input_loop
set /p NUM=整数を入力してください: 

:: 数値かどうか確認(set /a が失敗するか試す)
set /a TEST_NUM=%NUM% >nul 2>&1
if %errorlevel% neq 0 (
    echo [ERROR] 数値を入力してください。
    goto :input_loop
)

:: 0以上の整数かチェック
if %NUM% lss 0 (
    echo [ERROR] 0以上の値を入力してください。
    goto :input_loop
)

echo 入力値: %NUM%

ユーザー入力の受け取りと詳細なバリデーションは ユーザー入力を受け取る完全ガイド を参照してください。

5. 処理時間の計測方法

5-1. %TIME% を使った簡易計測(秒単位)

@echo off
setlocal

:: 開始時刻を取得(HH:MM:SS.mm 形式)
set START=%TIME%

:: ── 計測対象の処理 ──
timeout /t 3 /nobreak >nul
:: ─────────────────

:: 終了時刻を取得
set END=%TIME%

:: 時・分・秒・ミリ秒をそれぞれ取り出す
for /f "tokens=1-4 delims=:." %%A in ("%START%") do (
    set /a S_H=%%A, S_M=%%B, S_S=%%C, S_MS=%%D
)
for /f "tokens=1-4 delims=:." %%A in ("%END%") do (
    set /a E_H=%%A, E_M=%%B, E_S=%%C, E_MS=%%D
)

:: 開始・終了をミリ秒に変換して差分を計算
set /a START_MS=(%S_H%*3600+%S_M%*60+%S_S%)*100+%S_MS%
set /a END_MS=(%E_H%*3600+%E_M%*60+%E_S%)*100+%E_MS%
set /a ELAPSED_MS=%END_MS%-%START_MS%

:: 0:00 をまたぐ場合(日をまたいだ場合)の補正
if %ELAPSED_MS% lss 0 set /a ELAPSED_MS+=8640000

set /a ELAPSED_SEC=%ELAPSED_MS%/100
set /a ELAPSED_CSEC=%ELAPSED_MS%%%100
echo 処理時間: %ELAPSED_SEC%.%ELAPSED_CSEC% 秒

5-2. PowerShell Measure-Command で高精度計測

@echo off

:: PowerShell で処理時間を正確に計測
for /f %%T in ('powershell -Command "& { $sw = [System.Diagnostics.Stopwatch]::StartNew(); Start-Sleep -Seconds 2; $sw.Stop(); Write-Host $sw.Elapsed.TotalSeconds }"') do (
    set ELAPSED=%%T
)
echo 処理時間: %ELAPSED% 秒
%TIME% の落とし穴:地域設定によって区切り文字が変わる
一部の地域設定では %TIME% の区切り文字が :. でなく, になる場合があります。ミリ秒精度が必要な本番環境では PowerShell の Stopwatch クラスの方が確実です。

6. ファイルサイズの合計を計算する

@echo off
setlocal enabledelayedexpansion

set TOTAL_BYTES=0
set FILE_COUNT=0

:: カレントディレクトリの全 .log ファイルのサイズ合計を計算
for %%F in (C:logs*.log) do (
    set /a FILE_COUNT+=1

    :: %%~zF でファイルサイズ(byte)を取得
    set /a TOTAL_BYTES+=%%~zF
)

echo ファイル数: %FILE_COUNT%
echo 合計サイズ: %TOTAL_BYTES% bytes

:: KB・MB に変換して表示
set /a TOTAL_KB=%TOTAL_BYTES%/1024
set /a TOTAL_MB=%TOTAL_BYTES%/1048576
echo            %TOTAL_KB% KB
echo            %TOTAL_MB% MB
2GB 超えのファイルでは set /a がオーバーフローする
単一ファイルが 2GB (2,147,483,647 byte) を超えると %%~zF の値がset /a で正常に扱えなくなります。大容量ファイルのサイズ集計には PowerShell を使ってください。

6-1. PowerShell で大容量ファイルのサイズ集計

@echo off

:: 2GB 超えにも対応(PowerShell の [long] 型を活用)
for /f %%S in ('powershell -Command "(Get-ChildItem C:data*.bak | Measure-Object -Property Length -Sum).Sum"') do (
    set TOTAL_BYTES=%%S
)

for /f %%M in ('powershell -Command "Write-Host ([math]::Round(%TOTAL_BYTES% / 1GB, 2))"') do (
    set TOTAL_GB=%%M
)

echo 合計サイズ: %TOTAL_GB% GB

7. 16進数・8進数・2進数の変換

7-1. 16進数リテラルと変換

@echo off
setlocal

:: 16進数リテラル(0x プレフィックス)は set /a で直接使える
set /a HEX_VAL=0xFF
echo 0xFF = %HEX_VAL%

set /a PORT=0x1F90
echo 0x1F90 (8080) = %PORT%

:: 10進数 → 16進数 への変換は PowerShell を使う
for /f %%H in ('powershell -Command "Write-Host ([Convert]::ToString(255, 16).ToUpper())"') do set HEX=%%H
echo 255 を 16進数に変換: 0x%HEX%

:: 10進数 → 2進数
for /f %%B in ('powershell -Command "Write-Host ([Convert]::ToString(42, 2))"') do set BIN=%%B
echo 42 を 2進数に変換: %BIN%

:: 16進数 → 10進数
for /f %%D in ('powershell -Command "Write-Host ([Convert]::ToInt32(''1F'', 16))"') do set DEC=%%D
echo 0x1F を 10進数に変換: %DEC%
8進数リテラルにも注意
set /a r=010 の結果は 8 です(8進数リテラル)。先頭に 0 が付く数値は8進数と解釈されます。0809 はエラーになります(8進数に8・9は存在しない)。先頭0付きの数字(日付の月・日など)を計算に使う場合は注意してください。

7-2. 先頭0付きの数値を正しく計算する(日付処理の落とし穴)

@echo off
setlocal

:: 日付から月・日を取り出すと先頭0が付くことがある
:: 例: 2025/01/08 → MONTH=01, DAY=08
for /f "tokens=2" %%M in ('wmic os get LocalDateTime /value ^| find "LocalDateTime"') do set DT=%%M
set MONTH=%DT:~4,2%
set DAY=%DT:~6,2%

:: 先頭0を除去してから計算する
set /a MONTH_NUM=1%MONTH%-100
set /a DAY_NUM=1%DAY%-100

echo 月: %MONTH% → 計算用: %MONTH_NUM%
echo 日: %DAY% → 計算用: %DAY_NUM%

:: 先頭に 1 をつけて 100 を引くことで 0X → X に変換
:: 01 → 101 - 100 = 1
:: 08 → 108 - 100 = 8 (8進数エラー回避)

8. 実践例3本

実践例1:ログファイルの統計レポートを生成する

@echo off
setlocal enabledelayedexpansion

:: ログフォルダの統計: ファイル数・総行数・エラー件数・警告件数
set LOGDIR=C:applogs
set FILE_COUNT=0
set TOTAL_LINES=0
set ERROR_COUNT=0
set WARN_COUNT=0

for %%F in ("%LOGDIR%*.log") do (
    set /a FILE_COUNT+=1

    :: 行数カウント
    for /f %%N in ('type "%%F" ^| find /c /v ""') do set /a TOTAL_LINES+=%%N

    :: エラー件数カウント
    for /f %%N in ('type "%%F" ^| find /c "ERROR"') do set /a ERROR_COUNT+=%%N

    :: 警告件数カウント
    for /f %%N in ('type "%%F" ^| find /c "WARN"') do set /a WARN_COUNT+=%%N
)

:: 正常行数
set /a NORMAL_COUNT=%TOTAL_LINES%-%ERROR_COUNT%-%WARN_COUNT%

:: エラー率(整数・×100倍して計算)
set ERROR_RATE=N/A
if %TOTAL_LINES% gtr 0 (
    set /a ERROR_RATE_X100=%ERROR_COUNT%*10000/%TOTAL_LINES%
    set /a ERROR_RATE_INT=%ERROR_RATE_X100%/100
    set /a ERROR_RATE_DEC=%ERROR_RATE_X100%%%100
    set ERROR_RATE=%ERROR_RATE_INT%.%ERROR_RATE_DEC%
    set ERROR_RATE_UNIT=%%
)

echo ====================================
echo  ログ統計レポート
echo ====================================
echo  対象フォルダ : %LOGDIR%
echo  ファイル数   : %FILE_COUNT%
echo  総行数       : %TOTAL_LINES%
echo  ERROR        : %ERROR_COUNT%
echo  WARN         : %WARN_COUNT%
echo  正常         : %NORMAL_COUNT%
echo  エラー率     : %ERROR_RATE%%ERROR_RATE_UNIT%
echo ====================================

実践例2:スクリプトの処理時間を計測してログに記録する

@echo off
setlocal

:: ログファイル
set LOGFILE=C:logsperf_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log

:: 開始時刻を記録
set START=%TIME%
echo [%DATE% %TIME%] 処理開始 >> "%LOGFILE%"

:: ── 実際の処理(例:大量ファイルコピー)──
robocopy C:source D:backup /mir /r:2 /w:5 /nfl /ndl
set COPY_RESULT=%errorlevel%
:: ──────────────────────────────────────

:: 終了時刻を取得して経過時間を計算
set END=%TIME%

for /f "tokens=1-4 delims=:." %%A in ("%START%") do (
    set /a S_H=%%A, S_M=%%B, S_S=%%C, S_CS=%%D
)
for /f "tokens=1-4 delims=:." %%A in ("%END%") do (
    set /a E_H=%%A, E_M=%%B, E_S=%%C, E_CS=%%D
)

set /a START_CS=(%S_H%*3600+%S_M%*60+%S_S%)*100+%S_CS%
set /a END_CS=(%E_H%*3600+%E_M%*60+%E_S%)*100+%E_CS%
set /a ELAPSED=%END_CS%-%START_CS%
if %ELAPSED% lss 0 set /a ELAPSED+=8640000

set /a EL_SEC=%ELAPSED%/100
set /a EL_CS=%ELAPSED%%%100

:: ステータス判定(robocopy: 8以上はエラー)
if %COPY_RESULT% geq 8 (
    set STATUS=ERROR
) else (
    set STATUS=OK
)

echo [%DATE% %TIME%] 処理終了 STATUS=%STATUS% TIME=%EL_SEC%.%EL_CS%s >> "%LOGFILE%"
echo 処理時間: %EL_SEC%.%EL_CS% 秒 (ステータス: %STATUS%)

実践例3:ファイルサイズ閾値チェックとアーカイブ判定

@echo off
setlocal enabledelayedexpansion

:: 100MB を超えるログファイルをアーカイブ対象に分類
set LOGDIR=C:applogs
set THRESHOLD_MB=100
set /a THRESHOLD_BYTES=%THRESHOLD_MB%*1048576

set TOTAL_FILES=0
set ARCHIVE_COUNT=0
set TOTAL_MB=0

echo === ファイルサイズチェック (閾値: %THRESHOLD_MB% MB) ===

for %%F in ("%LOGDIR%*.log") do (
    set /a TOTAL_FILES+=1
    set FSIZE=%%~zF
    set /a FSIZE_MB=!FSIZE!/1048576

    if !FSIZE! gtr %THRESHOLD_BYTES% (
        set /a ARCHIVE_COUNT+=1
        echo [ARCHIVE] %%~nxF  (!FSIZE_MB! MB)
    ) else (
        echo [  OK   ] %%~nxF  (!FSIZE_MB! MB)
    )

    set /a TOTAL_MB+=!FSIZE_MB!
)

echo.
echo ファイル数: %TOTAL_FILES%
echo アーカイブ対象: %ARCHIVE_COUNT% 件
echo 合計サイズ: %TOTAL_MB% MB

if %ARCHIVE_COUNT% gtr 0 (
    echo.
    echo [INFO] アーカイブ処理を開始してください。
    exit /b 1
)
exit /b 0

数値比較(EQU / GTR / LSS の使い方)の詳細は 数値を比較する方法完全ガイド、FOR文の活用は FOR文の使い方完全ガイド も参照してください。

9. まとめ:計算パターン別チートシート

計算の種類 コマンド例
整数の四則演算 set /a R=%A%+%B%
インクリメント set /a COUNT+=1
剰余(余り) set /a R=%N%%%3(バッチ内は%%)
小数点計算 powershell -Command "Write-Host (1.5*2.3)"
平方根・べき乗 powershell -Command "[math]::Sqrt(16)"
合計をループで計算 for ... set /a TOTAL+=%%V
最大値・最小値 if %%V gtr !MAX! set /a MAX=%%V
処理時間計測 set START=%TIME% → 計算 → 差分を set /a
ファイルサイズ取得 for %%F in (*.log) do set /a SIZE+=%%~zF
16進数リテラル set /a R=0xFF
10進→16進変換 powershell "[Convert]::ToString(255, 16)"
先頭0の除去 set /a N=1%MONTH%-100(08→8 に変換)

FAQ

Qset /a で小数点を含む計算はできますか?

Aできません。set /a は 32bit 符号付き整数演算のみです。小数点計算が必要な場合は powershell -Command "Write-Host (1.5 + 2.3)" を使ってください。整数演算で近似する場合は「×10倍法」(10倍して計算、表示時に割り戻す)が使えます。

Qset /a の計算結果がおかしい(負の値になる)のはなぜですか?

A32bit 整数の上限(2,147,483,647)を超えてオーバーフローしている可能性があります。ファイルサイズの合計が 2GB を超えるケースなどで発生します。また、先頭に 0 が付く数値(08 など)は8進数と解釈されエラーになります。先頭0付きの数値は set /a N=1%VAR%-100 で除去してから計算してください。

Q%errorlevel% を set /a で計算に使えますか?

Aはい、使えます。set /a TOTAL_ERR+=%errorlevel% のように直接使えます。ただし set /a 自体が %errorlevel% を変更するため、計算前に別の変数に退避してから使う方が安全です(set ERR=%errorlevel%)。

Qfor ループ内で計算した結果が %VAR% で参照できません。

A遅延展開が必要です。setlocal enabledelayedexpansion をスクリプト先頭に追加し、ループ内では %%VAR%% ではなく !VAR! で参照してください。%VAR% はループ開始前の値を展開するため、ループ内で変更した値が見えません。

Qバッチで平均値を小数点付きで表示したいです。

Aset /a では整数しか扱えないため、以下のように PowerShell に渡してください:powershell -Command "Write-Host ([math]::Round(%TOTAL% / %COUNT%, 2))"。または整数部分と小数第1〜2位を別々に set /a で計算して文字列結合する方法もあります。

Q複数の変数を使った複雑な式を1行で書けますか?

Aはい、set /a は複数の演算子を含む式を1行で処理できます。例:set /a RESULT=(%A%+%B%)*%C%-%D%。カンマ区切りで複数の代入を1コマンドで行うことも可能です:set /a A=1, B=2, C=A+B