Skip to content

LongTail-Software/COM_BigDecimal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

53 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

COM_BigDecimal 仕様書

1. プロジェクト概要

COM_BigDecimal は Windows 上の COM クライアント向けに任意精度の十進演算を提供するコンポーネントです。金融・会計システムでの丸め誤差回避、科学技術計算の高精度化、スクリプト言語からの利用など、従来の DECIMAL 型では桁数が不足する領域を補完します。コンポーネントは ATL ベースで実装し、Automation (IDispatch) クライアントとの互換性を第一とします。

2. 想定ユースケース

  • Excel VBA や VBScript からの高精度通貨計算
  • .NET / C++ クライアントにおける金融リスク分析エンジン
  • PowerShell / Windows Script Host を利用したレポート自動化や検証ツール

3. システムおよび開発要件

  • 対応 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 用登録スクリプトを同梱予定

4. 提供モジュールと登録情報

種別 識別子 備考
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} 精度・丸め規則を管理

4.1 ATL 実装クラス構造

以下のクラス図は、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
Loading

5. インターフェース設計

5.1 共通設計方針

  • すべての公開インターフェースは IDispatch を継承するデュアルインターフェースとして実装し、Automation クライアントから利用可能にします。
  • IBigDecimal インスタンスはイミュータブルとし、演算メソッドは常に新しい IBigDecimal を返します。
  • 任意パラメーターは VARIANT で受け取り、VT_EMPTY または VT_ERROR (DISP_E_PARAMNOTFOUND) を検出して既定値を適用します。
  • 内部演算は十進基数を用い、IEEE 754 十進浮動小数点に準拠した丸めモードを提供します。

5.2 IBigDecimalFactory (IID: {3A9B6718-ED5E-4C3D-9F42-1D04BA5F1A8C})

メソッド 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 相当のキャッシュ済みインスタンスを返す

5.3 IBigDecimal (IID: {A94CFAD3-4177-4B08-AA0D-9BACEA2BBA2F})

メソッド 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 値をビッグエンディアンで取得

5.4 IBigDecimalContext (IID: {6E974FF3-ABE4-49D2-92F4-47E0D8A9797A})

メンバー シグネチャ 説明
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)

6. IDL スケッチ

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;
    };
};

7. エラー処理方針

  • すべてのメソッドは 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 に詳細メッセージを格納します。

8. スレッドモデルとパフォーマンス

  • 登録時の ThreadingModelBoth を指定し、STA/MTA クライアントの双方に対応します。
  • 実装は値オブジェクトのコピーを最小化するため参照カウント付きの内部ハンドルを利用します。演算結果は copy-on-write を採用し、並列呼び出しを安全にします。
  • 長大な演算 (桁数 10,000 超) 時は計算時間が伸びるため、IBigDecimalContext::MaxExponent を用いたガードとキャンセル用の IProgress 互換オブジェクト導入を検討します (将来拡張)。

9. バージョニングと互換性

  • バージョンは Semantic Versioning (MAJOR.MINOR.PATCH) に従います。MAJOR 変更時のみ API 非互換が許容されます。
  • Type Library のバージョンは 1.0 から開始し、MINOR 以上の更新時にバージョン番号をインクリメントします。
  • インターフェースの後方互換を維持するため、新規メソッドは末尾の DISPIDs に追加し既存の順序を変更しません。

10. テストおよび検証戦略

  • 単体テスト: C++ 単体テストで 4 つの代表スイート (基本演算、文字列変換、エラー処理、境界ケース) を用意。
  • 相互運用テスト: VBScript、PowerShell、C# (COM Interop)、C++ (ATL Smart Pointer) での接続確認スクリプトを自動化。
  • パフォーマンステスト: 1,000 桁・10,000 桁・100,000 桁のベンチマークを取得し、しきい値を README に掲載予定。
  • コード署名・強制 ASLR などセキュリティ設定を CI で検証。

11. 今後の拡張候補

  • IBigDecimalMath としてべき級数や特殊関数 (exp, log, sin 等) の追加
  • SAFEARRAY を用いたベクトル演算 API (AddRange, Sum, Dot) の提供
  • クロスプロセス IPC での大量データ受け渡しのための共有メモリバックエンド
  • .NET 7+ へのプライマリ Interop Assembly (PIA) 提供

12. 簡易使用例 (VBScript)

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()

13. ドキュメント更新方針

  • 実装されたメソッド、列挙値、エラーコードに変更が入る場合は Pull Request 内で README の対応箇所を更新します。
  • CHANGELOG.md を導入し、README にはハイレベルな仕様のみを保持します。
  • docs/BigDecimalFeatureCoverage.md に Java との機能差分と対応状況を集約します。
  • API サーフェスのスナップショットは docs/idl ディレクトリに IDL ファイルとして保存し、README から参照します。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages