Quantlib

Excel PasteSpecial Values 快捷按鈕導致 QuantLib 崩潰

  • November 5, 2020

當我使用 Excel 右鍵點擊工具欄上的快速訪問 PasteOptions/Values 按鈕時,我遇到了 QuantLibXL 的一個奇怪問題(為圖片道歉:擷取右鍵點擊菜單的螢幕抓取非常困難!)。

有沒有其他人經歷過這個?

在此處輸入圖像描述

如果我使用此按鈕粘貼特殊/值,而不是“粘貼特殊…”子菜單,則 QuantLib 似乎在內部崩潰並且對庫的所有呼叫都返回 #NUM!。唯一的解決方案是關閉並重新啟動 Excel。

這是一個重現問題的簡單表格(NB Excel 計算是自動的)。

在此處輸入圖像描述

用公式:

在此處輸入圖像描述

因此 qlCalendarAdvance() 函式採用參數 (B2),該參數本身就是函式 (=B1) 的結果。

重現錯誤的步驟:

  1. 選擇單元格 B1
  2. 右鍵點擊單元格 B2,然後選擇粘貼選項/值快捷按鈕(如上圖所示)。
  3. 單元格 B3 變為 #NUM!

筆記:

  1. 如果 B2 已經被硬編碼,則不會發生錯誤。
  2. 錯誤不會 100% 發生,儘管發生的頻率要高得多,這表明重新計算時存在某種時間問題。
  3. 顯然,解決方法是避免使用該按鈕(!)。

Excel:Microsoft 365 64 位。2009 版(內部版本 13231.20390)

QL 外掛:QuantLibXL-vc141-x64-mt-s-1_16_0.xll

在深入探勘之後,我在 QuantLibXL 基礎程式碼中發現了一個問題:建構子沒有處理異常。

在 QL 用於包裝 Excel4 C 樣式介面 (functioncall.cpp) 的基本程式碼中,有以下程式碼,其中該類設置了一個靜態指針以確保僅存在一個實例:

FunctionCall *FunctionCall::instance_ = 0;    

FunctionCall::FunctionCall(const std::string functionName) :
       functionName_(functionName), 
       callerDimensions_(CallerDimensions::Uninitialized),
       error_(false) {
   OH_REQUIRE(!instance_, "Multiple attempts to initialize global FunctionCall object");
   instance_ = this; //The issue is here

   Excel(xlfCaller, &xCaller_, 0);
   if (xCaller_->xltype == xltypeRef || xCaller_->xltype == xltypeSRef) {
       Excel(xlfReftext, &xReftext_, 1, &xCaller_);
       refStr_ = ConvertOper(xReftext_()); //THIS CAN FAIL 
       callerType_ = CallerType::Cell;
   } else if (xCaller_->xltype & xltypeErr) {
       callerType_ = CallerType::VBA;
   } else if (xCaller_->xltype == xltypeMulti) {
       callerType_ = CallerType::Menu;
   } else {
       callerType_ = CallerType::Unknown;
   }
}

問題似乎是,如果您使用的是右鍵點擊按鈕,Excel 界面將無法解析“呼叫者”(它告訴 UDF 如何呼叫它)。對 ConvertOper(xRefText…) 的呼叫會引發異常(因為它無法強制執行 Error OPER)。這不在建構子中處理,但在死前建構子程式碼已設置

instance_ = this;

由於解構子(將 instance_ 設置回 0)永遠不會被呼叫,以後對建構子的呼叫總是認為已經有一個實例,並且 OH_REQUIRE 斷言失敗。

畢竟,解決方案非常簡單:只需將設置實例的行移到可能引發異常的程式碼之後:

  //instance_ = this; MOVE FROM HERE 

   Excel(xlfCaller, &xCaller_, 0);
   if (xCaller_->xltype == xltypeRef || xCaller_->xltype == xltypeSRef) {
       Excel(xlfReftext, &xReftext_, 1, &xCaller_);
       refStr_ = ConvertOper(xReftext_()); //THIS CAN FAIL 
       callerType_ = CallerType::Cell;
   } else if (xCaller_->xltype & xltypeErr) {
       callerType_ = CallerType::VBA;
   } else if (xCaller_->xltype == xltypeMulti) {
       callerType_ = CallerType::Menu;
   } else {
       callerType_ = CallerType::Unknown;
   }

   instance_ = this; //TO HERE
}

重新編譯,一切正常。

引用自:https://quant.stackexchange.com/questions/59026