*

【コマンドプロンプト】32bit以上の計算をする方法(引き算)

コマンドプロンプトで計算するときに「Set /a ~」で計算式を使うと符号付32bitの間でしか計算ができない。

符号付32bitの範囲は「-2147483648 ~ 2147483647」であるため、この範囲の値でないと「Set /a ~」と入力した際にエラーとなるか、オーバーフローを起こし、正しい計算が行われない。

たとえば「2147483647 + 1」は「2147483648」になるはずだが「Set /a」で実行すると
下記の画像のように、「-2147483648」となってしまう。

SETコマンドでオーバーフロー

また、「Setコマンド」で「2147483647」を超える値をセットすると
「無効な数字です。数値は 32 ビットで表記される数値です。」と表示されエラーとなる

setコマンドエラー。無効な数字です。数値は32ビットで表記される数値です。

ということで、32bitを超える計算(引き算)を行う為にバッチを組んでみた。

正直、ものすごく強引だが、引き算はできた。

32bitを超える引き算の結果

問題は使い道がいまいち無いという。。。。

@echo off
setlocal enabledelayedexpansion
REM #################################################################
REM
REM コマンドプロンプトで32bitを越える引き算処理
REM
REM ※AがBを上回っていること。
REM
REM #################################################################

REM A-Bの値をセット
Set A=123456789101112
Set B=123451230568153

REM ==============================================================
REM 文字列カウント&一文字ずつ変数に格納処理
REM ==============================================================

REM -----------------------------------
REM Aの文字数カウント
REM -----------------------------------
call :strlen "%A%"

REM A文字数保存
set /a Acnt=%strlen%

REM -----------------------------------
REM Aを一文字ずつ配列に格納
REM -----------------------------------
call :DataArrStored A %Acnt%

REM -----------------------------------
REM Bの文字数カウント
REM -----------------------------------
call :strlen "%B%"

REM B文字数保存
set /a Bcnt=%strlen%

REM -----------------------------------
REM Bを一文字ずつ配列に格納
REM -----------------------------------
call :DataArrStored B %Bcnt%

REM ==============================================================
REM 計算処理(引き算)
REM ==============================================================

REM -----------------------------------
REM 計算処理
REM -----------------------------------
call :subtraction

REM -----------------------------------
REM 結果(result[i])を結合処理
REM -----------------------------------

REM iにAの文字数を代入
set /a i=%Acnt%
REM 配列から結果へ一文字(一番大きい位)を代入
set result=!result[%i%]!

:result_join
REM 配列が存在しない場合はループを抜ける
if "!result[%i%]!"=="" goto next1
REM 配列の添え字のカウントダウン
set /a i=%i%-1
REM 1文字結合
set result=%result%!result[%i%]!
goto result_join
:next1

REM -----------------------------------
REM %result%の先頭文字に「0」がある場合、除去
REM -----------------------------------

REM iの初期化
set /a i=-1
REM Aの文字数-1を代入
set /a tempAcnt=%Acnt%-1
:Zero_Del_Loop
set /a i=%i%+1
REM Aの文字数を超える場合(計算結果が0)
if %i% GTR %tempAcnt% goto next2
REM 先頭文字から比較し、0である場合、ループ
if "!result:~%i%,1%!"=="0" goto Zero_Del_Loop
:next2

REM 計算結果が全て0か
if "%i%" EQU "%Acnt%" (
   REM 結果に0を代入
   set result=0

REM それ以外
) else (
   REM 先頭から0を除く
   set result=!result:~%i%!
)

REM -----------------------------------
REM 結果(result)出力
REM -----------------------------------
echo A:%A% - B:%B%
echo.
echo 結果:%result%

pause

exit /b

REM #################################################################
REM
REM サブルーチン
REM
REM
REM
REM #################################################################
:strlen
REM ==================================================
REM 文字数カウント
REM ==================================================
   set strlen_string=%~1
   set strlen=0
   if "%strlen_string%"=="" goto :EOF
   :strlen_while
      call set ch=%%strlen_string:~%strlen%,1%%
      if "%ch%"=="" goto strlen_wend
      set /a strlen+=1
      goto strlen_while
   :strlen_wend
goto :EOF

:DataArrStored
REM ==================================================
REM 一文字ずつ配列として格納
REM ==================================================
   set Arr=%1
   set /a cnt=%2
   set /a i=1
   set /a cnt=%cnt%-1
   :DataArrStored_loop
   if %i% GTR !%Arr%cnt! goto :EOF
      set %Arr%[%i%]=!%Arr%:~%cnt%,1!
      set /a cnt=%cnt%-1
      set /a i=%i%+1
   goto DataArrStored_loop
goto :EOF

:subtraction
REM ==================================================
REM AとBの引き算
REM ==================================================
   set /a i=1
   :subtraction_loop

   REM A配列の要素数を超えた場合は終了
   if %i% GTR %Acnt% goto :EOF
   REM -----------------------------------
   REM B配列にデータが存在しない場合の処理
   REM -----------------------------------
   if "!B[%i%]!"=="" (
      REM iが最大値(Acnt)であるか
      if %i%==%Acnt% (
         REM A[i]がマイナスか
         if !A[%i%]! LSS 0 (
            REM resultへ0を入力
            set /a result[%i%]=0
            REM 次の位の処理へ
            goto next_number
         )
      ) else (
         REM A[i]がマイナスか
         if !A[%i%]! LSS 0 (
            REM A-Bの結果がマイナス値の場合、10足して計算し直す
            set /a result[%i%]=!A[%i%]!+10
            REM 次の位をマイナス1処理
            goto next_number_down
         )
      )
      REM Aの値をそのままresultへ
      set /a result[%i%]=!A[%i%]!
      REM 次の位の処理へ
      goto next_number
   )

   REM -----------------------------------
   REM A-Bの引き算処理
   REM -----------------------------------
   REM A-Bの結果をresult[i]へ
   set /a result[%i%]=!A[%i%]!-!B[%i%]!

   REM 引き算結果が0未満か判定
   if !result[%i%]! LSS 0 (
      REM A-Bの結果がマイナス値の場合、10足して計算し直す
      set /a result[%i%]=!A[%i%]!+10-!B[%i%]!
      REM 次の位をマイナス1処理
      goto next_number_down
   )

   :next_number
   REM -----------------------------------
   REM 通常のカウントアップ
   REM -----------------------------------
   set /a i=%i%+1
   goto subtraction_loop

   :next_number_down
   REM -----------------------------------
   REM カウントアップと次の位をマイナス1
   REM -----------------------------------
   set /a i=%i%+1
   REM 次の位から1引く
   set /a A[%i%]=!A[%i%]!-1
   goto subtraction_loop

goto :EOF

Adsense

関連記事

コマンドプロンプト

【コマンドプロンプト】前日日付、月末日付を変数に取得するバッチ。うるう年対応

コマンドプロンプトを使って前日、指定日、月末日付を変数に取得する。 「SearchDay」に入

記事を読む

コマンドプロンプト

【コマンドプロンプト】改行コード CR、LF、CRLFの出力とテキスト書き出し。

仕事でバッチファイルを使っているとログ出力が非常に大事になる。 細かくログを出すことによって、

記事を読む

コマンドプロンプト

【コマンドプロンプト】バッチファイルでCSVを1行ずつ処理をする方法

僕はプログラマーではないので、あまりカッコイイプログラムはかけませんが、CSVファイルを1行ずつ、バ

記事を読む

データベース

【コマンドプロンプト】完成版!cmdでSQLの結果を変数に取得

以前、 【コマンドプロンプト】cmdでSQLの結果を変数に取得する方法 を書きましたが、

記事を読む

データベース

【コマンドプロンプト】cmdでSQLの結果を変数に取得する方法

力技の取得方法をご紹介。というかメモ。 題名には偉そうに書きましたが…なかなか良い方法が見つか

記事を読む

コマンドプロンプト

【コマンドプロンプト】バッチでセクション付のINIファイルの読み込み

バッチファイルでINIファイルから値を読み込む 1.INIファイルの用意 以下の「バッチファイル

記事を読む

コマンドプロンプト

【コマンドプロンプト】net use で共有フォルダに接続できない場合。

  システム エラー 1219 が発生しました。 同じユーザーによる、サーバー

記事を読む

コマンドプロンプト

【コマンドプロンプト】前後の不要なスペースの除去(取り除く)

コマンドプロンプトのFOR文とか使って変数に取得しようとすると、取得元のコマンドとかファイルによって

記事を読む

Adsense

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Adsense

Microsoft Office
【Access】削除クエリの「指定されたテーブルから削除できませんでした。」の対処法

削除クエリで「指定されたテーブルから削除できませんでした。」と ポッ

Microsoft Office
【PowerPoint】表や図形、画像オブジェクトの位置をピッタリ合わせる方法

パワーポイントで、図形や画像等のオブジェクトの細かい位置調整は、 完

データベース
【SQL Server】Excel VBAのレコードセットを使ってテーブルの一括更新

前々回は読み取り専用でレコードセットへ取得し、結果をエクセルへ書き出し

application
【Visual Studio】デバック、ブレークポイントで止まらない。

Visual Studio 2015でVB.netのプログラムをデバッ

データベース
【SQL Server】Excel VBAでSELECT文を実行してレコードセットへ取得

前回は、テーブルのレコードをVBAで直接更新(Insert/updat

→もっと見る

PAGE TOP ↑