Posts Tagged With: Excel

[Excel]白做工了,規劃求解與 VBA


很久沒有做分析了,都在 code …

上個月老闆交代我做個分析,想來想去,想要最佳化還是用數學規劃,線性規劃是個快速解決問題的方法,只要問題不複雜,直接用線性規劃求解就可以了。

問題是離開學校後,沒有好的軟體可以算線性規劃,想起來還有 Excel 的規劃求解可以用,就翻開 Excel 玩。

話說 2005 年在新加坡 MVP亞洲年會中,跟當時負責中文化的洪士吉老師與這個巨集的澳洲原作者聊過,當時聽洪士吉老師有原始碼跟密碼,我那時自己也用 VBScript 寫一個線性規劃的 ASP 線上網頁,所以主要討論的是卡曼卡法的加速解跟 Lindo,但是我論文不是搞這方向,離開學校後就甩到邊邊角角了。

我平常為了加速 Excel 開啟,所有的增益集都關閉,Office 2003 年代短暫的玩過規劃求解,但主要還是玩 Lindo ,開啟規劃求解增益集後,發覺設定方式完全不一樣了,看了一下線上手冊,上面寫 Excel 2010 後改成這樣,只好重新學習。

首先,先把自己寫的線性規劃翻出來,用相同的模型建構 Excel ,自己會比較容易上手:

線性規劃命題範例

按下 [進行最佳化分析] 後,可得到計算結果:

線性規劃計算結果

這個命題是在做教材範例,假定一個有閘門的滯洪池或水庫,在已知預報進水量下,受到滯洪池蓄洪量、放水路放水等限制,目標是穩定洩水減低洪害,各限制式的依據參閱上面網頁擷圖右側文字說明。

下面是我喜歡的規劃求解表格樣式,規劃求解仍然使用 Excel 公式,所以並沒有需要排得整整齊齊,但是為了人類容易閱讀,還是排成表格方式比較不會錯,詳細個位置說明,放到最後,先看操作步驟:

在 Sheet 上建立規劃求解命題

從 選單 點選 [資料] > [規劃求解] ,逐項設定:

規劃求解設定

規劃求解計算約 1 秒內可完成:

規劃求解完成

計算結果與設定對話盒連結註記說明:

規劃求解計算完成
  1. 圖上數字對應到 [規劃求解參數] 對話盒的數字,並不對應到這邊說明的項次。
  2. 變數名我選擇放在第一列,C1 ~ J1 ,這種架構大家都容易看得懂。
  3. 變數計算結果我選擇放在第二列,C2 ~ J2,預設可以不輸入,參見前面建立命題的圖,不輸入,就代表起始解為 {0} 集合。
  4. 目標函數的係數我放在 C3 ~ J3,也就是 MIN C。
  5. 限制式左側的係數我放在 C4 ~ J19 ,不等號我放在 M4 ~ M19,常數項我放在 N4 ~ N19。
  6. 最佳化可以在 [規劃求解參數] 輸入 Excel 公式,但這樣會造成每次設定的複雜化,比如說目標函數一變,或是限制式調整時, [規劃求解參數] 的設定就要跟著變,所以為了方便起見,建議像我這樣做,在 K3 輸入陣列公式,讓係數乘變數,就可以降低 [規劃求解參數] 的設定問題,K3 正確設定完成後,複製到 K4 ~ K19 ,讓限制式的係數一樣可以乘變數。注意,陣列公式輸入完成後,要按下 {Shift}+{Ctrl}+{Enter} 三個鍵,才能正確變成陣列公式。
  7. 最後在 [規劃求解參數] 對話盒 [載入/儲存] 按鈕,點下 [儲存] ,選擇 N2 。

這個計算結果,可以透過 K/L/M 三欄檢查限制式是否成立,或是直接觀看 N 欄,限制式成立的邏輯公式就是使用 K/L/M 三欄。

在說明項目 6 中,使用了陣列公式,實務上會增加計算量,也就是係數 0 x 變數,但卻可以讓設定參數簡易許多,就如同本例。

做到這,可以發現 L 欄用不到,因為在 [規劃求解參數] 對話盒 [新增] 限制式時,都要手動輸入,我的目的是要解決老闆交付的任務,所以針對此命題範例建立了測試的 VBA 程式碼,細節到正式命題再修改:

用 VBA 建立規劃求解參數

為了方便起見,我在 VBA 內直接建立陣列公式,也就是說上面建立規劃求解的途中,K 欄不用輸入,其他 [規劃求解參數] 對話盒的輸入,都用 VBA 自動產生。

規劃求解不支援直接輸入不等式,所以用 GetRelationIndex 函數將不等式轉成索引值輸入。

如果不想自己打太多程式碼,可以用錄製的再進行修改,不過這張圖上的程式碼已經很精簡了,錄製會很亂,不如直接打,再改欄位值即可。

規劃求解的函數使用說明參考微軟官方網址:https://docs.microsoft.com/zh-tw/office/vba/excel/concepts/functions/using-the-solver-vba-functions

好了,終於開始建立正式命題,先把正式命題縮小為一天24小時的時資料進行連續量分析,建個小小的模型,測試看看是不是能正常運作:

規劃求解超過上限

不得不爆粗口…

「規劃求解限定為 200 個變數儲存格和 100 個限制式,加上變數儲存格的限值。」

100 個限制式?這個規格限制下,根本是玩具吧… 規劃求解,我只好繼續把你放生了…

[2019/06/05]

花了點時間,把網頁版 ASP 的 VBScript 轉成 VBNET 語法,順便把命題轉成類別,測試還算成功。

VBNET WinForm 輸入命題
VBNET WinForm 輸入命題

輸入完線性規劃命題後,點選 [限制式] 頁籤 下方工具列那個圖示 (測試程式沒有管 Icon 的美觀度) ,即可得到輸出結果,輸出改用 StringBuilder 產生 HTML 語法用 WebBrowser Control 輸出,這樣之後若有需要,可以在工具列放預覽列印的按鈕,呼叫 WebBrowser Control 的預覽列印。

VBNET WinForm 輸出結果
VBNET WinForm 輸出結果

不過裡面還有一些 Bug ,大型命題解不出來,這就造成除錯困難,大概還要加一頁來輸出線性規劃各步驟階段的計算表格,才好除錯。

廣告
Categories: Office, 工作點滴, 技術分享 | 標籤: | 發表留言

[WU] 10 月份 Windows Update 後,Excel ODBC/Oledb 異常


目前已知 10 月份 Windows Update 更新問題將會導致使用
Microsoft Jet 4.0 的 Excel Driver 會出問題,資料庫連線字串使用:
ODBC={Microsoft Excel Driver (*.xls)}
Provider=Microsoft.Jet.OLEDB.4.0;

無法正常使用。

由於目前 Windows Update 均為彙總套件更新,暫時無法鎖定問題發生在哪個 KB 。

緊急應變需先改用:
ODBC={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)}
Provider=Microsoft.ACE.OLEDB.12.0;

以上的資料庫連線字串版本。

如需同時安裝不同位元版本 x86/x64 的 driver ,需安裝不同 Office 版本才行,例如 Office 2016 x64 + Office 2013 x86 的 driver ,請依據個人電腦內使用 Office 版本搭配:
在微軟下載中心搜尋時,使用關鍵字為 Access Runtime :
2016: https://www.microsoft.com/zh-tw/download/details.aspx?id=50040
2013: https://www.microsoft.com/zh-TW/download/details.aspx?id=39358
2010: https://www.microsoft.com/zh-tw/download/details.aspx?id=10910
2007: https://www.microsoft.com/zh-tw/download/details.aspx?id=4438
註:2007 僅有 x86 版本。

一般來說,建議安裝最新版本的 Access Runtime ,也就是 2016/2013 ,但千萬記住,安裝前先確認自己電腦 Office 版本與位元版本。

在 VS2017 透過 ODBC 開啟 Excel 檔可以列舉資料庫結構,但不能顯示資料,如下圖:

VS2017 ODBC Excel 錯誤畫面

VS2017 ODBC Excel 錯誤畫面

軟體觸發錯誤事件的錯誤訊息為:
ERROR [HY000] [Microsoft][ODBC Excel Driver] 保留錯誤 (-5016);這個錯誤並無訊息。
ERROR [01000] [Microsoft][ODBC Excel Driver]一般警告 無法開啟登錄鍵 ‘Temporary (volatile) Jet DSN for process 0xeb4 Thread 0x23ac DBC 0x16bd6cf4 Excel’。
ERROR [IM006] [Microsoft][ODBC 驅動程式管理員] 驅動程式的 SQLSetConnectAttr 失敗

事件檢視器畫面如下:

事件檢視器 ODBC Excel 錯誤畫面

事件檢視器 ODBC Excel 錯誤畫面

目前微軟論壇討論可參考這篇:
https://social.msdn.microsoft.com/Forums/en-US/2feac7ff-3fbd-4d46-afdc-65341762f753/odbc-excel-driver-stopped-working-with-unexpected-error-from-external-database-driver-1?forum=sqldataaccess

由於是底層錯誤,所以不管是 ADO / ADO.NET / MFC 等,只要使用到這個資料庫連線字串的,都會掛。

Categories: 工作點滴, 更新與回報 | 標籤: | 5 則迴響

[WU]安全性更新後 Excel 很慢、且無法開啟檔案


這個月的安全性更新中, Office 更新完後,公司部分電腦的 Excel 發生異常,直接點檔案兩次,會跳出:

傳送命令給程式時發生錯誤

Windows 找不到檔案路徑\檔案名稱,請確定您輸入正確的名稱,然後再試一次

所以依照 DDE 的標準方式處置,包含移除非微軟的增益集,其中發現了奇怪的現象,如圖,會出現:

excel_addon_01

符號表工具列 增益集

 

在 增益集設定中 ,出現硬碟找不到實體路徑的 Office 2007 (office12) 的增益集 [Chinese Translation Addin]

excel_addon_02

增益集 [Chinese Translation Addin]

 

試過修復 Office 也沒用,開新帳號測試,結果新帳號正常。

研判應該是註冊資訊檔異常。

1. 關閉 Excel ,由於 Excel 異常,可能無法正常關閉,請務必使用工作管理員確認 Excel 關閉。
2. 將下列機碼的 Excel 改成 Excel.old

Excel 2010
HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Excel
HKEY_LOCAL_MACHINE\Software\Microsoft\Office\14.0\Excel

Excel 2013
HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Excel
HKEY_LOCAL_MACHINE\Software\Microsoft\Office\15.0\Excel

註:部分電腦 HKEY_LOCAL_MACHINE 下可能沒有 Excel ,若沒有可忽略

3. 從開始工具列捷徑 開啟 Excel ,頁籤應已無 標點符號增益集
4. Excel 選項 > 增益集 > COM增益集 > 把不存在的增益集刪除
5. 關閉 Excel ,對著一般 excel 檔案點兩下,看是否正常開啟。
6. 正常開啟後,可把機碼 Excel.old 刪除,收工。

目前發現會出問題無法正常開啟的是 Office 2010/2013 x86 。
Office 2007 有碰上加入這個工具列,但可能本來就是 Office 2007 的增益集,因此不會發生衝突,不用可停用。

我懷疑是微軟封裝更新時,忘了把機碼移除,導致大家死得很難看。

參考:https://support.microsoft.com/zh-tw/help/280504/how-to-troubleshoot-startup-problems-in-excel

註:這周小紅傘更新後,預設排程每 168 小時全機掃描一次,好像變成每 168 分鐘掃描一次,也造成 Excel 很慢,暫時先停用排程,建議大家也看看小紅傘事件紀錄。

Categories: 工作點滴, 更新與回報 | 標籤: | 1 則迴響

[VBA] LongLong 超長整數


話說,公司的專案支援 VBScript 外掛,這幾天在用 Excel 2013 的 VBA 7.1 寫 VBScript 。

因為裡面要用到位元旗標,我就很順手的打了:
2^i

想說,VBA 原始碼自動感知會幫我加空白,就繼續往下寫。

寫完以後用 Excel 測試,變成 #VALUE ,就用追蹤方式追查,才知道這行有問題。

手動改成 2 ^ i 就沒問題,好奇之下另外開個小專案測試:

誤使用到超長整數符號

誤使用到超長整數符號

用除錯模式看,型別居然是 LongLong 。

按下 F2 查物件類別庫,果然有 LongLong ,用 HEX(-1) 測試,是 8 bytes 的超長整數:

LongLong 為 8 bytes 超長整數

LongLong 為 8 bytes 超長整數

用 Google 搜尋 MSDN ,看起來是 x64 版本的 VBA 就加入了,應該是 Office 2010 x64 以後開始有此功能:
64 位元 Visual Basic for Applications 概觀:https://msdn.microsoft.com/zh-tw/library/office/Gg264421.aspx

順便回頭測了 Excel 2003 的 VBA 6.5:

Excel 2003 VBA 6.5 正確處理次方運算符號

Excel 2003 VBA 6.5 正確處理次方運算符號

舊版本的 VBA 就能自動把 2^2 轉成 2 ^ 2 。

從 LongLong 超長整數的 VBA 7.1 來看當初微軟在 2005 年宣告 VB6 不再支援的理由又消滅了一個,不是不能支援 64 bits 及加超長整數,而是不願意加,是不為也,非不能也。

Categories: 工作點滴, 技術分享 | 標籤: | 2 則迴響

Excel Variant Date 在 1900/3/1 以前的基準日與 VB6 不同


這個狀況更詳細的說明可以到 http://support.microsoft.com/ 搜尋 Excel 1900 。
簡單的說,最早的試算表 Lotus 123 把 1900 視為閏年,理論上來說,逢四閏、逢百不閏、逢四百閏,所以 1900 年為非閏年,但是在 Excel 會有 1900/2/29 的存在,當時的設計是為了與 Lotus 123 相容而存在,就用到現在,所以到了 Excel 2007 還是這樣…
Excel 有兩組日期系統,以 1900/1/0 為 基準或是 1904/1/1 為基準。下面是個簡表,Variant Date 為 OleAut32.dll 裡面定義的 Variant Date ,VB6/VBA/VBScript 的內建 Date 型態,VBNET 可用 ToOADate/FromOADate 轉換,核心值域是依據 IEEE 754 的 Double 來設計,所以加上 Double 的對照:
Double Variant Date Excel Date 1904 Date
0 1899/12/30 1900/1/0 1904/1/1
1 1899/12/31 1900/1/1 1904/1/2
2 1900/1/1 1900/1/2 1904/1/3
58 1900/2/26 1900/2/27 1904/2/28
59 1900/2/27 1900/2/28 1904/2/29
60 1900/2/28 1900/2/29 1904/3/1
61 1900/3/1 1900/3/1 1904/3/2
62 1900/3/2 1900/3/2 1904/3/3
Variant Date 在 1900/3/1 以後就完全與 Excel Date 重合,基本上不建議採用 1904 為基礎的日期資料。
可以看出來,Excel Date 居然有個 1900/1/0 ,算是很有趣的東西,此外,Excel 不接受基準日以前的日期,所以不能有 1899/12/31 這類的日期出現,當然,若採用 1904 為基準,就完全不會出現 1904 年以前的日期。
因此在 1900/3/1 以前的日期若仍要使用在 Excel 內,必須改用 VBA 來處理,並運用 String <-> Date 來相互轉換。
Categories: Office | 標籤: | 發表留言

在WordPress.com寫網誌.

%d 位部落客按了讚: