作者legnaleurc (CA)
看板C_and_CPP
標題Re: [問題] 數值分析 class / template 設計模式問題
時間Fri Jun 1 19:38:18 2012
※ 引述《EdisonX (閉上眼的魚)》之銘言:
:
: Q1 class with function pointer
:
: 一種方式是在 C1 裡面塞外部的 function pointer
: class C1{
: private:
: double (*fptr)(double) ;
: public :
: C1 ( double (*fptr_)(double) ) : fptr (fptr_) {}
: double run(double low, double up) {
: fptr(low); .... fptr(up);
: }
: };
: 這種方法好處是可以多弄一個 setter , 隨時改掉 fptr 指向函式
: < 又是一個問題,我不知道這種 class 大多從頭到尾指向一個 function,
: 還是可以中途切到其他的 function 去 ... >
這個方式的耦合度比較低, 也可以隨時換 strategy
但是如果該 function 需要帶 context, 就要用 std::function + std::bind
: 另一種方式以 pure virtual function , 便必需強制繼承撰之
: class Base {
: prvate :
: virtual double fitness(double) = 0;
: public :
: double run(double low, double up) {
: fitness(low), ..., fitness(up);
: }
: }
繼承關係的耦合度很強, 看你怎麼抉擇
: 另外,好奇有沒有像這種東西 < 我知道它是錯的 orz >
: class C <typename Func> {
: public :
: double run(double low, double up) {
: Func(low), ... , Func(up) ;
: }
: };
有, 但是有點差異:
template< typename Function >
double run( double low, double up, Function f ) {
f( low, up );
}
這樣它會自己推導 prototype
: 請問一般在設計時會怎做 ?
老問題, 設計 API 最後就是選擇, 沒什麼標準答案
: Q2 我真搞不懂 template 該什麼時候拿出來用..
:
: 有些 template function 確實是很直覺有個設計之範本,如
: template <typename T>
: T MaxVal(T* beg, T* end);
: template <typename T>
: T Sum(T* beg, T* end);
: 納悶的是一些明明很特別的數值計算上,比方說算平均值好了
: 這個很明顯最後傳回的會是 double,還有必要做成 template 嗎?
: template <typename Tin , typename Tout>
: Tout Average(Tin* beg, Tin* end);
: < 其實我更納悶的是, std::complex 做成 template 有必要嗎 ? >
: < 一般在做的時候不都是直接塞 double 進去就好了 ? >
有的時候你可能會想塞自己做的數值型態
比方說一個 class Double 對精準度有做特化
那麼這個 class 可以直接丟進去, 一樣受益於既有的演算法
:
: Q3 <牛角一> : operator == 是單元運算子,但有時候...
:
: 在判斷是否相等之情況下
: class C {
: private :
: double num;
: public :
: bool operator == (const C& other, const double eps=1E-9) const {
: return fabs (num - other.num ) <= eps;
: }
: };
雖然不是重點, 但這裡語法錯誤
基本上 operator overloads 最好都寫成 friend free function
: compiler error, 不意外。目前想到折衷的做法是
: 新增一個 static data member, const static double eps ,
: 但其初值便只能用 coder 自定吧 ?
: 若使用之 eps 不同時就不能用 == , 必須再額外寫一個
: bool C::IsEqu(const C& other, const double eps = 1E-9) const;
: 還是這部份根本沒人在鳥 floating error ?
我看不太懂這段, 但是 const double 在這裡是無意義的
因為 pass by value 之後 eps 的值本來就不會有 side effect
:
: Q4 <牛角二> : overload subscript of subscript operator...
:
: 簡單的說是這個東西
: template <typename T>
: class M{
: public:
: T operator [][] (const size_t row, const size_t col) ;
: };
: 請問,唯一方法是否只能架構起類似 vector<> 的東西,再用繼承方式處理嗎 ?
: ( 這裡也是一個問題 , 我認為用 "包含" 較佳 , 但一些設計是用繼承處理 )
: 這裡我沒打算用 std::vector 原因是認為對 Matrix 而言,
: col / row 一旦固定幾乎不會變,
: 用 vector 在效能與空間管理上「主觀」認為並不吃香,
: 不知我的想法是否有誤 ?
基本上, 你的 Matrix 可以 overload [], 讓它回傳 Row
這個 Row 可以再 overload [] 一次
另外 vector 在空間與效率上反而是最好的, 因為
1. 空間連續
2. 它的額外成本很低
3. 你幾乎不需要刪除節點, 所以它要 realloc 的機率很低
真的覺得不放心的話
可參考 boost::array
: PS :
: 我是有想過用這種方式去做
: template <typename T, const size_t row, const size_t col>
: class M {
: T arr[row][col];
: };
: 一樣產生兩個問題 , 這種方式應是放在 stack, 可使用量較小,
: 另一問題又回到 operator [][] 方面,
: 目前想過可以用 T operator( const size_t row, const size_t col) ; 方式做
: < 但總覺得寫起來很不順 >
:
: Q5 <牛角三> : 防呆問題
:
: 1. 到底是誰該負責準確性 ?
: // < part 1 >
: double div(double a, double b) {
: return a/b;
: }
: double a, b, c;
: if(fabs(b) > eps) c = div(a,b) ;
: else /* error handle */
: // < part 2 >
: double div(double a, double b) {
: assert(fabs(b)>eps)
: return a/b;
: }
: double a, b, c
: c = div(a,b);
: 一般而言是弄得像 part1 還是 part 2 ?
: 或 , 這是公司內互踢皮球的開始 ?
文件講好就好, 這是政治問題
這也呼應了上述 Q2, 保留彈性總有一天會用到
: 2. 記憶體不夠到底要不要處理 ?
: 一般抓到什麼除零錯誤、字串格式不對 都還有可議空間 ,
: 把有問題的那段抓出來分析還有機會改善。
: 但判定 allocate memory fail 時
: new fail. malloc fail. 有不同方式可 catch ,
: 除了 log 紀錄起來、程式強制退出,還有其他處理方式嗎?
這邊很複雜, 建議可參考 More Effective C++ 最後幾個章節
專門講述你要怎麼在記憶體不足的情況再擠出空間
但強制退出也是一個可接受方案
: -------------------------------
: 小弟學不專精,問題有些多,煩請不吝賜教。
: 謝謝各位。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.115.53.41
→ loveme00835:using friend function is bad idea in this 06/01 20:02
→ loveme00835:situation, becuz operators just provide convenient 06/01 20:03
→ loveme00835:ways to interactive with objects, but that should 06/01 20:04
→ loveme00835:the 'only' way to do this, so ususlly objects also 06/01 20:05
→ loveme00835:give you methods like a.equals(b) 06/01 20:05
→ legnaleurc:我覺得不需要太妖魔化 friend, 因為 C++ 缺乏 package 06/01 20:29
→ legnaleurc:scope permission, 另外, operator 的另一個好處是它可 06/01 20:29
→ legnaleurc:以跟 primitive types 的操作一致化, 對於數值語義來說 06/01 20:30
→ legnaleurc:有其好處 06/01 20:31
→ loveme00835:you're right, but it might increase probability of 06/01 20:34
→ loveme00835:ambiguous function calls 06/01 20:35
→ legnaleurc:等等, 我覺得我們在講的論點我好像在 news group 上看 06/01 20:38
→ legnaleurc:過 XD 反正各有優缺點, 最後都是選擇問題 06/01 20:39
→ EdisonX:Q3 的部份我補充一下,實際上是 class complex 實作上我的 06/01 20:42
→ EdisonX:作法,在判斷兩個norm是否相同時,考慮浮點數誤差,所以會有 06/01 20:42
→ EdisonX:eps,原意operator==那裡可能語法真不容許,故問一般強調的 06/01 20:43
→ EdisonX:eps不同時,只剩 member func./friend func. 一路而已吧 ? 06/01 20:45
→ legnaleurc:同樣的功能, 同時提供 operator 和具名函式的做法也不 06/01 20:47
→ legnaleurc:少, 如果讓我設計的話, 我會使用 static member 06/01 20:48
→ legnaleurc:operator 的版本使用 static member 的 eps 06/01 20:49
推 EdisonX:指的是文中提到的 Complex::static const double eps 嗎 ? 06/01 20:49
→ legnaleurc:具名函式讓 client 指定 eps, 這沒有定論, 不要太違反 06/01 20:50
→ legnaleurc:直覺就好 06/01 20:50
→ loveme00835:用proxy多型取得誤差值,此法每個物件要keep指標,可 06/01 20:50
→ loveme00835:以執行期更換criteria,不一致再比較取小者 06/01 20:53
→ EdisonX:疑!love~大的方法似乎也可每個物件都一個 eps 取小實現. 06/01 20:56
→ EdisonX:此討論串真是受益良多.再次感謝不吝指導 :) 06/01 20:57
推 EdisonX:補個推, 謝謝 legnaleurc 細心的回覆, 一點 p 幣請笑納。 06/01 21:01
→ legnaleurc: :) loveme00835 展示的方法都很實用, 我也見識不少 06/01 21:32