0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Excel VBA PowershellのBigIntを使って多倍長整数(多数桁)計算をする

Last updated at Posted at 2021-05-09

Powsershellの多倍長桁の計算は[math]::ではない

[bigint]::Add(4,5)

ついでにDecimalも

[decimal]::Add(4,5)

英語は色々

Multiple integer
multiple-precision integer
ここからMPIと略す場合もある。
multiple length arithmeti
C#では整数型は桁数が限られているのでそれを超えるとBigNum そして整数を強調する場合にはBigInt
そもそも「多倍長」ってどういう意味?

標準的なデータ型を複数組み合わせ,64bitより長い数値を扱う計算全般を広義の多倍長(multiple precision)計算と呼ぶことにする。もっとも主題は多倍長の実数型を使用する数値計算(numerical computation)なので,特に断らない限り,double型より長い実数型を扱う数値計算を多倍長計算と呼ぶ。これらの多倍長計算は標準的なfloat型,double型を使用した数値計算に比べて多大な計算時間を要するのが普通である。

可変精度(variable precision)計算,任意精度(arbitrary precision)計算という言葉を使用すると良い。無限精度(infinite precision)計算

という呼び方もあります。まあ無限精度は実態と違うのでありえないかな。
多倍長精度数値計算 GNU MP,MPFR,QDによるプログラミング
という本の筆者でもある。いや売れないというよりは一家に一冊は必須ですよね。(まがお)

確かにPowershellhaBigIntを扱えても、例えばGPGPUで計算させるということはできません。
GPGPUを用いたソフトウェア高速化手法

BigInt とDecimalの違い

当然ながら桁数に制限がある

[decimal]::MinValue
[decimal]::MaxValue

+-79228162514264337593543950335
((64^2)^2)^2

また小数は+-1e-28までいけます
ただし、整数位の桁数が増えるほど、扱える桁数は減ります。桁数は29で固定されているわけです。
128ビット浮動小数点
というのは29桁固定で小数点だけが浮動するという意味のようです。
また、小数がある場合、文字列として囲んだほうがいいです
また、溢れた桁数は、四捨五入されます。BigIntは切り捨てです。

[decimal]1.12345678901234567890123456
# 1.12345678901235
[decimal]'1.12345678901234567890123456'
# 1.12345678901234567890123456
[decimal]'10.12345678901234567890123456789'
10.123456789012345678901234568

Windows Powershell 5.1においてはリテラル文字がある

X = 4.3 - 4.2 このとき、Xの値は?(前編)

$( 4.3d - 4.2d)
[math]::Equals( $(4.3d - 4.2d) , 0.1d)

ライブラリをインストールしなくてもこのようにdをつけると、演算誤差がなくなります。

PowershellのDecimalの小数点以下はすごく癖がある

BigIntもそうなので、変更しましたが、小数点以下も書いていないけどそうなんですけど、桁数が多いと勝手にDoubleにします。

数値リテラルについて

大きな値のリテラルの解析
以前は、より高い整数値は、他の型にキャストされる前に double として解析されていました。 その結果、より高い範囲で精度が低下します。 次に例を示します。

PS> [bigint]111111111111111111111111111111111111111111111111111111
111111111111111100905595216014112456735339620444667904


> この問題を回避するには、値を文字列として書き込み、次のように変換する必要がありました。

>```powershell
PS> [bigint]'111111111111111111111111111111111111111111111111111111'
111111111111111111111111111111111111111111111111111111

1enは22まで

それ以上はおかしくなる。文字列で囲んでもエラーになる。Powを使うと正確になる。
`1e23'はDecimalのほうが正確

[bigint]1e23
# 99999999999999991611392
PS C:\Users\very_> [bigint]1e22
# 10000000000000000000000
[bigint]::Pow(10,30)
# 1000000000000000000000000000000
[decimal]1e24
1000000000000000000000000

使用するPowershellはWindows Powershell 5.1

数値リテラルについて
なので、BigIntegerのリテラルとかは使えません。
また、上記の文字列として扱わないと精度が低下する現象が起きる可能性があります。

bigintは切り捨てらしい

符号付き整数であり、小数点以下は切り捨て処理されます。このへんがDecimalと違います。
非推奨の[long]のリテラルL1.2Lとすると11.5Lとすると2になります。
BigIntの切り捨ての挙動は他のものと異なります。

このため、Powで平方根を求めることができない

[math]::pow(4 , 0.5)であれば2が求められます。
しかし、 BigIntは整数になるので指数に小数点をもたせらません。
[BigInt]::pow(4 , 0.5)は1になってしまいます。

演算誤差と同様、比較の結果が異なる可能性

0以下は切り捨てみたいですが、四捨五入でも比較演算子の結果は変わる可能性があります。

Powershell 5.1ではBigIntは16進数が扱える

桁数が大きいとBigInt扱いになる
長さが8の倍数である16進数の最初の桁が8以上の場合、その数字は負として扱われます。

$(0x8ffffffFFFffffFF) -as [bigint]
# -8070450532247928833
$(0x7ffffffFFFffffFF) -as [bigint]
# 9223372036854775807

Powershell7.1ではバイナリ(2進数)が扱えますが、Powershell5.1では使えません。
また、BigInterの説明はPowershellにはなく.Netにしかありません
BigInteger 構造体
ただしこのままだと.NET5.0でPowershell5.1と合わないです。
BigInteger 構造体 .Net FrameWork 4.5.1
くらいが良さそうです。

BigIntの正式名称

[System.Numerics.BigInteger]
名前空間:
System.Numerics
アセンブリ:
System.Runtime.Numerics.dll

wsh run

PowerShell VBAでPowerShellを実行して結果を取得する(Run編)【初実験編08】
今回はこういう複雑なことはしません。

その代わり参照設定

VBScript Regular Expression 5.5
WSHController
MSForms( FM20.Dll)
正規表現は数字かどうかの判定に使います
WSHはもちろんRunに
MSFormsはクリップボードに使います。
image.png

ClipBoardを使う

方法としては
クリップボードをクリアする
Powershellで計算結果をClipさせる
させたデータを取得する
クリップボードの内容がクリアされるのが欠点です
また、これではうまく行かないときはClipboardFormsを使います。

ExcelならではのClipboardForms

Clipboardformsは結果的にあまり使いませんでしたが、Excelにしかないようです。
この変数はSet 命令ではないです。しかも、Arrayで入るようです。

正規表現はマイナスを拾う

-1のような数でも[0-9\.]{1,}は拾います。
小数点のためにピリオドを入れています。

コードは以下の通り

加算、減算、乗算、除算、べき乗、Log10、絶対値、等しいかどうか、abのどちらが大きいか、Min Maxそして変わったところでは最大公約数やModPow(べき乗数除算余り)があります。Ver2.0でLogも加えました。ただし bが底になります。
加算はマイナスがつけられますので、これで減算もできます。ただし[bigInt]::MinusOneを使ったほうがいいです。

整数なら無限大まで使えるが

計算が無理なのでできない。このため、めちゃくちゃに大きい数とかは無理です。しかし30桁くらいまでは大丈夫でしょう。

Option Explicit
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' VBA For Microsoft Eexcel + Windows Powershell 5.1
''' Ver 2.0 20210509
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 参照設定
''' Microsoft VBScript Regular Expression Ver5.5
''' Windows Script Host Object Model
''' MSForm 2.0
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 加算 '''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintADD(a As String, b As String) As String
' 加算
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [BigInt]::Add( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintADD = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintADD = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 減算 '''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintSubtract(a As String, b As String) As String
' 減算 a - b
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [BigInt]::Add( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintSubtract = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintSubtract = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 乗法 '''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintMultiply(a As String, b As String) As String
' a x b 乗法
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [bigint]::Multiply( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintMultiply = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintMultiply = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 冪乗 '''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintPOW(a As String, b As String) As String
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [BigInt]::pow( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintPOW = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintPOW = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 除算 ’’’
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintDIVID(a As String, b As String) As String
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Divide( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintDIVID = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintDIVID = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 比較
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintCompare(a As String, b As String) As Long
' 左 a と 右 bを比較し、左が小さければ-1 等しい場合は 0 左が大きい場合は 1を返す
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Compare( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintCompare = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintCompare = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 最大値
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintMax(a As String, b As String) As String
' 左 a と 右 bを比較し、大きい値を返す エラーは0
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Max( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintMax = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintMax = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 等しいか
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintEQUALs(a As String, b As String) As Boolean
' 左 a と 右 bを比較し、等しいならTrue Boolean エラーもFalseを返す
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Equals( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintEQUALs = CBool(apClip(1))
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintEQUALs = False
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 最小値
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintMIN(a As String, b As String) As Long
' 左 a と 右 bを比較し、小さい値を返す エラーは0
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Max( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintMIN = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintMIN = 0
End If
Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 絶対値
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintABS(a As String) As String
' 絶対値を返す ただしテキスト、さらに小数点以下は切り捨て
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::ABS( '" & a & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintABS = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintABS = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' Log10
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintLOG10(a As String) As String
' Log10 のときの値を返す  a は小数点以下切りて、返り値は小数点以下は切り捨てではないある程度桁数がある
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [bigint]::LOG10( '" & PowerShellBigintABS(a) & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintLOG10 = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintLOG10 = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 否定 もしくは-1を掛けた値
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintNegate(a As String) As String
' a * (-1) の結果を返す
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [bigint]::Negate( '" & a & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintNegate = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintNegate = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 剰余
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintRemainder(a As String, b As String) As String
' a 被除数(割られる数) b 除数(割る数) a /bを実行し余りを返す 5/2 = 2 余り  1 なので1を返す
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ; [bigint]::Remainder( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.GetText
PowerShellBigintRemainder = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintRemainder = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 冪乗剰余
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintModPow(baseNumber As String, exponentNumber As String, DivisionNumber) As String
'  (a ^ b) mod cの値を返す冪乗余り bとcは0だとエラー
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(baseNumber) And Reg.Test(exponentNumber) And Reg.Test(DivisionNumber) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::modpow( '" & baseNumber & "' , '" & exponentNumber & "' ,'" & DivisionNumber & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintModPow = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintModPow = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' 最大公約数
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintGreatestCommonDivisor(a As String, b As String) As String
'  a と b の最大公約数
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::GreatestCommonDivisor( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintGreatestCommonDivisor = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintGreatestCommonDivisor = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' Log
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function PowerShellBigintLog(a As String, b As String) As String
'  Logb a
' Example PowerShellBigintLog("100","10")  Ans. 2
'             PowerShellBigintLog("10","100")  Ans. 0.5
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) And Reg.Test(b) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Log( '" & a & "' , '" & b & "' ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
oMSClp.GetFromClipboard
'ActiveCell.Value = oMSClp.gettext
PowerShellBigintLog = oMSClp.GetText
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintLog = 0
End If

Set oMSClp = Nothing
Set Reg = Nothing
Set WSH = Nothing
End Function

0除算チェックがうまくいかない

Function PowerShellBigintEQBigZero(a As String) As Boolean
' 0 除算エラーを回避するためにはBigINTにParseしてBigIntの0と比較する
Dim oMSClp As New DataObject
Dim WSH As New IWshRuntimeLibrary.WshShell
Dim Reg As New RegExp
Dim cmdStr As String
Dim apClip As Variant
On Error GoTo Eat
oMSClp.Clear
apClip = Application.ClipboardFormats
Reg.Global = True
Reg.MultiLine = False
Reg.Pattern = "[0-9\.]{1,}"
If Reg.Test(a) Then
cmdStr = "Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Equals([bigint]::Parse(" & a & "),  [bigint]::Zero ) | Clip"
WSH.Run cmdStr, 0, True
Else
GoTo Eat
End If
' oMSClp.GetFromClipboard
' ActiveCell.Value = oMSClp.GetText
PowerShellBigintEQBigZero = CBool(apClip(1))
GoTo Eat
Exit Function
Eat:
If Err.Number <> 0 Then
Debug.Print Err.Number, Err.Description: Err.Clear
PowerShellBigintEQBigZero = 0
End If
Exit Function
End Function
 Powershell -NoLogo Set-ExecutionPolicy RemoteSigned -Scope Process -f ;  [bigint]::Equals([bigint]::Parse(0),  [bigint]::Zero ) 

Trueが返ります
?PowerShellBigintEQBigZero(0)
Falseが返ります

実用性はあるだろう

これも大量の計算には向かないが、そもそも多倍長整数の演算を大量にやらせるのかという問題がある。
それにこういうVBAからパワーシェルを呼び出すと往々にしてマルウエア扱いされる。
しかし、多倍長桁の計算のコードを組んだり検証するのは容易ではない。
仮に組んだとしてもやはり遅い。
また、2の1万乗のような極端にステップ数が多い計算は何をやっても遅い。
すると、数が多かったり、時間がかかる場合以外では多少使えるかもしれない。
ただ、0除算処理などのエラー処理がないので、そのへんをどうするのかが課題。
というのも、例えば0.1はゼロではないが、BigIntは小数点以下を切り捨てるので、0になる。
仕様として小数点以下は切り捨てになる。というのが比較に影響するし、除算エラーにも影響する。
また2つの「数」は両方とも多倍長整数で、1でも多倍長整数扱いである。というのも要注意。返り値も一部の例外を除きテキストだ。
しかし、これは贅沢な悩みだろう。今までそもそも多倍長整数の演算のコードすら組めなかったのだから。
また、BigIntを使う人ははそういうをの理解して使うはずだからだ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?