COM_BigDecimal は Windows 上の COM クライアント向けに任意精度の十進演算を提供するコンポーネントです。金融・会計システムでの丸め誤差回避、科学技術計算の高精度化、スクリプト言語からの利用など、従来の DECIMAL 型では桁数が不足する領域を補完します。コンポーネントは ATL ベースで実装し、Automation (IDispatch) クライアントとの互換性を第一とします。
- Excel VBA や VBScript からの高精度通貨計算
- .NET / C++ クライアントにおける金融リスク分析エンジン
- PowerShell / Windows Script Host を利用したレポート自動化や検証ツール
- 対応 OS: Windows 10 21H2 以降 / Windows 11 (x86 および x64)
- ビルド環境: Visual Studio 2022 (v143) + ATL, Windows SDK 10.0.22621 以降
- 依存ライブラリ: 標準 C++17, ATL, 任意精度演算には内部で Boost.Multiprecision (ヘッダーオンリー) を想定
- COM 登録:
regsvr32配置、PowerShell 用登録スクリプトを同梱予定
| 種別 | 識別子 | 備考 |
|---|---|---|
| Type Library | LIBID_COMBigDecimalLib = {5E9A5B46-28D5-4A76-A86E-2B21A5D6E3F0} | COM_BigDecimal.tlb として配置 |
| COM クラス | CLSID_BigDecimalFactory = {4CF60E3D-1AFA-44E6-9B9C-BFB7C4D59B8C} | ユーザーが CoCreate する唯一のクラス |
| COM クラス | CLSID_BigDecimalContext = {1216E8AC-1274-4C37-A7E0-050AB3A3BCE1} | 既定コンテキスト生成用、Automation で扱いやすいよう CreateObject 対応 |
| インターフェース | IID_IBigDecimalFactory = {3A9B6718-ED5E-4C3D-9F42-1D04BA5F1A8C} | デュアルインターフェース |
| インターフェース | IID_IBigDecimal = {A94CFAD3-4177-4B08-AA0D-9BACEA2BBA2F} | すべての値オブジェクトが実装 |
| インターフェース | IID_IBigDecimalContext = {6E974FF3-ABE4-49D2-92F4-47E0D8A9797A} | 精度・丸め規則を管理 |
以下のクラス図は、ATL ベースの主要クラスと内部データ構造の依存関係を示します。
classDiagram
direction TB
class CCOMBigDecimalModule {
+DllCanUnloadNow()
+DllGetClassObject(...)
+DllRegisterServer()
+DllUnregisterServer()
+DllInstall(...)
}
class CBigDecimalFactory {
+CreateFromString(...)
+CreateFromInt64(...)
+CreateContext(...)
+GetVersion(...)
}
class CBigDecimalContext {
-m_data : shared_ptr<BigDecimalContextData>
+get_Precision()
+put_Precision()
+Merge(...)
+GetContextDataHandle()
}
class CBigDecimalValue {
-m_value : shared_ptr<BigDecimalValueData>
-m_context : shared_ptr<BigDecimalContextData>
+Arithmetic APIs
+GetValueDataHandle()
+GetContextDataHandle()
}
class BigDecimalContextData {
+precision : LONG
+precisionMode : PrecisionMode
+isPrecisionExplicit : bool
+scale : optional<int>
+isScaleExplicit : bool
+roundingMode : BigDecimalRoundingMode
+clampExcessPrecision : bool
+maxExponent : LONG
}
class BigDecimalValueData {
+value : BigFloat
+unscaled : cpp_int
+scale : int
+hasTrailingZeros : bool
+storedPrecision : LONG
+storedPrecisionMode : PrecisionMode
+storedPrecisionExplicit : bool
+storedScale : optional<int>
+storedScaleExplicit : bool
}
class IBigDecimalFactory
class IBigDecimalContext
class IBigDecimal
class IBigDecimalContextNativeAccess
class IBigDecimalNativeAccess
CCOMBigDecimalModule --> CBigDecimalFactory : exports
CCOMBigDecimalModule --> CBigDecimalContext : exports
CBigDecimalFactory ..|> IBigDecimalFactory
CBigDecimalFactory o--> CBigDecimalContext : CreateContext()
CBigDecimalFactory o--> CBigDecimalValue : CreateValueInstance()
CBigDecimalContext ..|> IBigDecimalContext
CBigDecimalContext ..|> IBigDecimalContextNativeAccess
CBigDecimalContext --> BigDecimalContextData
CBigDecimalValue ..|> IBigDecimal
CBigDecimalValue ..|> IBigDecimalNativeAccess
CBigDecimalValue --> BigDecimalContextData
CBigDecimalValue --> BigDecimalValueData
- すべての公開インターフェースは
IDispatchを継承するデュアルインターフェースとして実装し、Automation クライアントから利用可能にします。 IBigDecimalインスタンスはイミュータブルとし、演算メソッドは常に新しいIBigDecimalを返します。- 任意パラメーターは
VARIANTで受け取り、VT_EMPTYまたはVT_ERROR (DISP_E_PARAMNOTFOUND)を検出して既定値を適用します。 - 内部演算は十進基数を用い、IEEE 754 十進浮動小数点に準拠した丸めモードを提供します。
| メソッド ID | シグネチャ | 説明 |
|---|---|---|
| 1 | HRESULT CreateFromString([in] BSTR value, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
文字列を解析して値を生成(指数表記・先頭プラス・空白無視に対応) |
| 2 | HRESULT CreateFromInt64([in] LONGLONG value, [in] LONG scale, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
64bit 整数とスケールから生成 |
| 3 | HRESULT CreateFromDecimal([in] DECIMAL value, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
COM の DECIMAL を変換し、必要に応じてコンテキストを適用 |
| 4 | HRESULT CreateFromBinary([in] SAFEARRAY(BYTE) magnitude, [in] VARIANT_BOOL isNegative, [in] LONG scale, [out, retval] IBigDecimal** result); |
base-10^9 チャンク配列から生成(従来 API) |
| 5 | HRESULT CreateContext([out, retval] IBigDecimalContext** context); |
計算コンテキストを新規生成 |
| 6 | HRESULT GetVersion([out, retval] BSTR* semanticVersion); |
major.minor.patch 形式のバージョン文字列を返す |
| 7 | HRESULT CreateFromDouble([in] DOUBLE value, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
double から生成。NaN/±∞ は BD_E_NUMBER_FORMAT を返す |
| 8 | HRESULT CreateFromBigIntegerBinary([in] SAFEARRAY(BYTE) magnitude, [in] VARIANT_BOOL isNegative, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
ビッグエンディアンの 2 進バイト列で渡された BigInteger から生成 |
| 9 | HRESULT CreateFromCharArray([in] SAFEARRAY(wchar_t) characters, [in] LONG offset, [in] LONG length, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
文字配列の部分列をパースして生成(CreateFromString と同じルール) |
| 10 | HRESULT CreateFromUnscaledValue([in] SAFEARRAY(BYTE) magnitude, [in] VARIANT_BOOL isNegative, [in] LONG scale, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
非スケール値(ビッグエンディアン)とスケール指定から生成 |
| 11 | HRESULT GetZero([out, retval] IBigDecimal** result); |
Java BigDecimal.ZERO 相当のキャッシュ済みインスタンスを返す |
| 12 | HRESULT GetOne([out, retval] IBigDecimal** result); |
Java BigDecimal.ONE 相当のキャッシュ済みインスタンスを返す |
| 13 | HRESULT GetTen([out, retval] IBigDecimal** result); |
Java BigDecimal.TEN 相当のキャッシュ済みインスタンスを返す |
| メソッド ID | シグネチャ | 説明 |
|---|---|---|
| 1 | HRESULT get_Precision([out, retval] LONG* precision); |
現在の有効桁数を取得 |
| 2 | HRESULT get_Scale([out, retval] LONG* scale); |
小数点以下桁数を取得 |
| 3 | HRESULT get_IsZero([out, retval] VARIANT_BOOL* isZero); |
ゼロかどうかを判定 |
| 4 | HRESULT ToString([in, optional] LONG radix, [in, optional] VARIANT context, [out, retval] BSTR* text); |
文字列化 (既定 10 進、radix は 2/8/10/16/36 をサポート) |
| 5 | HRESULT ToDecimal([out, retval] DECIMAL* value); |
28 桁超過時は BD_E_OVERFLOW |
| 6 | HRESULT ToCurrency([out, retval] CURRENCY* value); |
4 桁丸めで通貨値に変換 |
| 7 | HRESULT Add([in] IBigDecimal* value, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
加算。context 未指定時は被演算子の最大精度を使用 |
| 8 | HRESULT Subtract([in] IBigDecimal* value, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
減算 |
| 9 | HRESULT Multiply([in] IBigDecimal* value, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
乗算 |
| 10 | HRESULT Divide([in] IBigDecimal* divisor, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
MathContext 指定で除算 |
| 11 | HRESULT Power([in] LONG exponent, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
指数演算 (指数は ±1,000,000 まで) |
| 12 | HRESULT Sqrt([in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
平方根。負数入力で BD_E_DOMAIN |
| 13 | HRESULT Negate([out, retval] IBigDecimal** result); |
符号反転 |
| 14 | HRESULT Abs([out, retval] IBigDecimal** result); |
絶対値 |
| 15 | HRESULT CompareTo([in] IBigDecimal* other, [out, retval] LONG* comparison); |
比較結果を -1/0/1 で返却 |
| 16 | HRESULT Round([in] LONG scale, [in] BigDecimalRoundingMode mode, [out, retval] IBigDecimal** result); |
旧 API。内部で SetScale を委譲 |
| 17 | HRESULT Shift([in] LONG digits, [out, retval] IBigDecimal** result); |
10^digits 倍でスケールを移動 |
| 18 | HRESULT Clone([out, retval] IBigDecimal** copy); |
ディープコピー |
| 19 | HRESULT DivideWithMode([in] IBigDecimal* divisor, [in] BigDecimalRoundingMode mode, [out, retval] IBigDecimal** result); |
丸めモードを明示した除算。UNNECESSARY 違反で BD_E_ARITHMETIC |
| 20 | HRESULT DivideToIntegralValue([in] IBigDecimal* divisor, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
商の整数部のみを取得。MathContext 適用時は BD_E_PRECISION_REQUIRED |
| 21 | HRESULT Remainder([in] IBigDecimal* divisor, [out, retval] IBigDecimal** result); |
this − divisor × integral を返す |
| 22 | HRESULT DivideAndRemainder([in] IBigDecimal* divisor, [out] IBigDecimal** quotient, [out] IBigDecimal** remainder, [in, optional] VARIANT context); |
商・剰余を同時取得 |
| 23 | HRESULT RemainderWithContext([in] IBigDecimal* divisor, [in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
剰余に MathContext を適用 |
| 24 | HRESULT SetScaleExact([in] LONG scale, [out, retval] IBigDecimal** result); |
setScale(scale) 相当。丸めが必要なら BD_E_PRECISION_REQUIRED |
| 25 | HRESULT SetScale([in] LONG scale, [in] BigDecimalRoundingMode mode, [out, retval] IBigDecimal** result); |
setScale(scale, mode) 相当 |
| 26 | HRESULT RoundWithContext([in] IBigDecimalContext* context, [out, retval] IBigDecimal** result); |
round(MathContext) 相当。精度低下時は BD_S_PRECISION_LOSS |
| 27 | HRESULT Plus([in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
Java plus()/plus(MathContext) 相当 |
| 28 | HRESULT Signum([out, retval] LONG* signum); |
符号を -1/0/1 で返す |
| 29 | HRESULT Min([in] IBigDecimal* value, [out, retval] IBigDecimal** result); |
数値比較で小さい方を返す |
| 30 | HRESULT Max([in] IBigDecimal* value, [out, retval] IBigDecimal** result); |
数値比較で大きい方を返す |
| 31 | HRESULT AbsWithContext([in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
MathContext 付き abs |
| 32 | HRESULT NegateWithContext([in, optional] VARIANT context, [out, retval] IBigDecimal** result); |
MathContext 付き negate |
| 33 | HRESULT StripTrailingZeros([out, retval] IBigDecimal** result); |
末尾ゼロとスケールを Java と同様に調整 |
| 34 | HRESULT Ulp([out, retval] IBigDecimal** result); |
現在の値に対する単位の最小値 |
| 35 | HRESULT EqualsExact([in] IBigDecimal* other, [out, retval] VARIANT_BOOL* isEqual); |
値だけでなく unscaled 値と scale を比較 |
| 36 | HRESULT ToPlainString([in, optional] VARIANT context, [out, retval] BSTR* text); |
指数表記を使わない文字列化 |
| 37 | HRESULT ToEngineeringString([in, optional] VARIANT context, [out, retval] BSTR* text); |
エンジニアリング表記で文字列化 |
| 38 | HRESULT ToInt32([out, retval] LONG* value); |
32bit 符号付整数へ変換。溢れは BD_E_OVERFLOW |
| 39 | HRESULT ToInt32Exact([out, retval] LONG* value); |
小数部や桁溢れがあると BD_E_ARITHMETIC |
| 40 | HRESULT ToInt64([out, retval] LONGLONG* value); |
64bit 符号付整数へ変換 |
| 41 | HRESULT ToInt64Exact([out, retval] LONGLONG* value); |
小数部や桁溢れがあると BD_E_ARITHMETIC |
| 42 | HRESULT ToDouble([out, retval] DOUBLE* value); |
IEEE754 double に変換。非正規/溢れは BD_E_OVERFLOW |
| 43 | HRESULT ToBigInteger([out] SAFEARRAY(BYTE)* magnitude, [out, retval] VARIANT_BOOL* isNegative); |
BigInteger 等価のバイト列を返す |
| 44 | HRESULT ToBigIntegerExact([out] SAFEARRAY(BYTE)* magnitude, [out, retval] VARIANT_BOOL* isNegative); |
非整数の場合は BD_E_ARITHMETIC |
| 45 | HRESULT UnscaledValueAsBinary([out] SAFEARRAY(BYTE)* magnitude, [out, retval] VARIANT_BOOL* isNegative); |
Unscaled 値をビッグエンディアンで取得 |
| メンバー | シグネチャ | 説明 |
|---|---|---|
| Precision | HRESULT get_Precision([out, retval] LONG* value); / HRESULT put_Precision([in] LONG value); |
0 の場合は無制限 (有効桁数) |
| Scale | HRESULT get_Scale([out, retval] LONG* value); / HRESULT put_Scale([in] LONG value); |
-1 を指定すると自動設定に戻る (内部は std::optional) |
| RoundingMode | HRESULT get_RoundingMode([out, retval] BigDecimalRoundingMode* mode); / HRESULT put_RoundingMode([in] BigDecimalRoundingMode mode); |
IEEE 754 の 8 種類 + 05UP 拡張 |
| ClampExcessPrecision | HRESULT get_ClampExcessPrecision([out, retval] VARIANT_BOOL* value); / HRESULT put_ClampExcessPrecision([in] VARIANT_BOOL value); |
true で指定桁数超過時は BD_E_PRECISION_REQUIRED を返し丸めを拒否 |
| MaxExponent | HRESULT get_MaxExponent([out, retval] LONG* value); / HRESULT put_MaxExponent([in] LONG value); |
正規化時の最大指数 (既定 1,000,000) |
| ResetDefaults | HRESULT ResetDefaults(); |
既定値にリセット |
| Merge | HRESULT Merge([in] IBigDecimalContext* override); |
他コンテキストを上書きマージ |
BigDecimalRoundingMode 列挙は以下を提供します。
BDRoundUp(0)BDRoundDown(1)BDRoundCeiling(2)BDRoundFloor(3)BDRoundHalfUp(4)BDRoundHalfDown(5)BDRoundHalfEven(6)BDRoundUnnecessary(7)BDRound05Up(8)
library COMBigDecimalLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
typedef [v1_enum] enum BigDecimalRoundingMode {
BDRoundUp = 0,
BDRoundDown = 1,
BDRoundCeiling = 2,
BDRoundFloor = 3,
BDRoundHalfUp = 4,
BDRoundHalfDown = 5,
BDRoundHalfEven = 6,
BDRoundUnnecessary = 7,
BDRound05Up = 8
} BigDecimalRoundingMode;
[uuid(6E974FF3-ABE4-49D2-92F4-47E0D8A9797A)]
interface IBigDecimalContext : IDispatch { /* プロパティ定義 */ };
[uuid(A94CFAD3-4177-4B08-AA0D-9BACEA2BBA2F)]
interface IBigDecimal : IDispatch { /* メソッド定義 */ };
[uuid(3A9B6718-ED5E-4C3D-9F42-1D04BA5F1A8C)]
interface IBigDecimalFactory : IDispatch { /* ファクトリメソッド */ };
[uuid(4CF60E3D-1AFA-44E6-9B9C-BFB7C4D59B8C)]
coclass BigDecimalFactory
{
[default] interface IBigDecimalFactory;
};
[uuid(1216E8AC-1274-4C37-A7E0-050AB3A3BCE1)]
coclass BigDecimalContext
{
[default] interface IBigDecimalContext;
};
};-
すべてのメソッドは
HRESULTを返却し、成功時はS_OK、注意喚起はSUCCEEDED(hr)かつBD_S_*を使用します。 -
重要なエラーコード (FACILITY_ITF = 0x4BD):
BD_E_INVALID_FORMAT= 0x8004BD01: バイナリ/チャンク配列などの入力形式が不正BD_E_DIVIDE_BY_ZERO= 0x8004BD02: 0 除算BD_E_OVERFLOW= 0x8004BD03: コンテキストの桁数・指数上限を超過BD_E_UNSUPPORTED_RADIX= 0x8004BD04:ToStringに未対応の基数を指定BD_E_DOMAIN= 0x8004BD05: 定義域外の演算BD_E_CONTEXT_REQUIRED= 0x8004BD06: MathContext が必須なのにVT_EMPTYが渡されたBD_E_PRECISION_REQUIRED= 0x8004BD07: コンテキストの桁数制約を満たさないBD_E_ARITHMETIC= 0x8004BD08: 整数除算で丸め指示が無い/剰余計算で追加情報が必要BD_E_NUMBER_FORMAT= 0x8004BD09: 文字列・double・char 配列の解析に失敗BD_S_PRECISION_LOSS= 0x0004BD10: 端数丸めによる精度低下
-
Automation クライアント向けに
IErrorInfoを実装し、Descriptionに詳細メッセージを格納します。
- 登録時の
ThreadingModelはBothを指定し、STA/MTA クライアントの双方に対応します。 - 実装は値オブジェクトのコピーを最小化するため参照カウント付きの内部ハンドルを利用します。演算結果は copy-on-write を採用し、並列呼び出しを安全にします。
- 長大な演算 (桁数 10,000 超) 時は計算時間が伸びるため、
IBigDecimalContext::MaxExponentを用いたガードとキャンセル用のIProgress互換オブジェクト導入を検討します (将来拡張)。
- バージョンは Semantic Versioning (
MAJOR.MINOR.PATCH) に従います。MAJOR 変更時のみ API 非互換が許容されます。 - Type Library のバージョンは 1.0 から開始し、
MINOR以上の更新時にバージョン番号をインクリメントします。 - インターフェースの後方互換を維持するため、新規メソッドは末尾の DISPIDs に追加し既存の順序を変更しません。
- 単体テスト: C++ 単体テストで 4 つの代表スイート (基本演算、文字列変換、エラー処理、境界ケース) を用意。
- 相互運用テスト: VBScript、PowerShell、C# (COM Interop)、C++ (ATL Smart Pointer) での接続確認スクリプトを自動化。
- パフォーマンステスト: 1,000 桁・10,000 桁・100,000 桁のベンチマークを取得し、しきい値を README に掲載予定。
- コード署名・強制 ASLR などセキュリティ設定を CI で検証。
IBigDecimalMathとしてべき級数や特殊関数 (exp, log, sin 等) の追加SAFEARRAYを用いたベクトル演算 API (AddRange,Sum,Dot) の提供- クロスプロセス IPC での大量データ受け渡しのための共有メモリバックエンド
- .NET 7+ へのプライマリ Interop Assembly (PIA) 提供
Dim factory, ctx, a, b, sum
Set factory = CreateObject("COM.BigDecimal.Factory")
Set ctx = factory.CreateContext()
ctx.Precision = 50
ctx.RoundingMode = BDRoundHalfEven
Set a = factory.CreateFromString("3.14159265358979323846264338327950288419716939937510", ctx)
Set b = factory.CreateFromString("2.71828182845904523536028747135266249775724709369995", ctx)
Set sum = a.Add(b, ctx)
WScript.Echo "π + e = " & sum.ToString()- 実装されたメソッド、列挙値、エラーコードに変更が入る場合は Pull Request 内で README の対応箇所を更新します。
CHANGELOG.mdを導入し、README にはハイレベルな仕様のみを保持します。docs/BigDecimalFeatureCoverage.mdに Java との機能差分と対応状況を集約します。- API サーフェスのスナップショットは
docs/idlディレクトリに IDL ファイルとして保存し、README から参照します。