#ifndef vectorX_h
#define vectorX_h
#include <limits>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
template <typename Type> //每個template只會包含他下面那個物件或函式,因此多個函式都要用template得每個都寫
class vectorX:public vector<Type>
{
private:
//vector<Type> vec; //因為整個vectorX都是繼承自vector,包括vector的member variable,因此不需要再多設一個vector來存資料
public:
/*vectorX<Type>(int num = 0, Type value = 0) //constructor,插入數字版本
{
for(vector<Type>::size_type i = 0; i < num, i++)
{
vec.push_back(value);
}
vSize = num;
};*/
vectorX(int num = 0, Type value = 0):vector<Type>(num, value) //constructor,插入數字版本。直接繼承std::vector裡寫好的constructor的寫法
{
};
vectorX<Type>(int num, const Type* input):vector<Type>(input, input + num) //constructor,插入陣列版本。直接繼承std::vector裡寫好的constructor的寫法
{
//vec<Type>(input, input + num);
//vSize = num;
};
/*vectorX<Type>(const vectorX& v) //copy constructor
{
vec = v;
vSize = v.vSize;
};*/
vectorX(const vectorX& v):vector<Type>(v) //copy constructor。直接繼承std::vector裡寫好的constructor的寫法
{
};
/*Type& operator[](int place)
{
if(place < 0)
return vec[0];
else if(place >= vSize)
return vec[vSize - 1];
else
return vec[place];
};*/
vectorX<Type> sum()
{
int tail = size(); //記錄尾巴
Type reg = 0; //紀錄加總
vectorX<Type> v = *this; //由於直接繼承vector裡的member variable,因此要用該vector時以"*this"的形式來呼叫。多創一個vectorX<Type> v來存是怕動到資料的內容
if(numeric_limits<Type>::is_signed)
//numeric_limits<要判斷的型態>::is_signed會判斷該型態是否為signed,是的話會回傳true
//這裡要先判斷是否為singed的原因,是因為如果是unsigned數,就一定都是正的,那只要一直加到vector爆炸就好,不需要先sort起來
{
sort(v.begin(), v.end()); //sort排序,未定義的話預設為由小排到大。括弧裡前面給要排的vector的頭,然後看要排vector裡幾個元素就加多少。全排就直接end()
//如果sort過後的vector中第一個數字就比0大,那整條vector都大於0,一直往後加就好
if(*(v.begin()) >= 0)
{
for(int head = 0; head < tail; head++)
{
if((numeric_limits<Type>::max() / 2) - (reg / 2) < (v[head] / 2))
//不能寫"reg + vec[head] > numeric_limits<Type>::max()",因為如果左邊已經爆掉了,那會產生無法預知的結果
throw OverLargest();
else
reg += v[head];
}
return reg; //一直都沒有爆掉的話就回傳
}
//如果sort過後的vector中最後一個數字比0還小,那整條vector都小於0,一直往後加就好
if(v[tail - 1] <= 0)
{
for(int head = 0; head < tail; head++)
{
if((-numeric_limits<Type>::max() / 2) - (reg / 2) > (v[head] / 2))
throw OverLowest();
else
reg += v[head];
}
return reg;
}
/*
如果vector中有負有正,就把頭尾頭尾加在一起,一直這樣往後加
因為signed有負有正,可能把一條vector裡的負數或正數都加起來就爆了,但全部加起來卻沒爆
因此先sort過使vector內元素由小排到大之後,頭尾加起來,比較能夠避免這種情況
*/
for(int head = 0; head < tail; head++)
{
/*
可能的情形:
1.頭尾加起來大於最大限制→代表頭尾之間的元素都已經大於0→爆掉回傳OverLargest
2.頭尾加起來小於最小限制→代表頭尾之間的元素都已經小於0→爆掉回傳OverLowest
3.頭尾加起來在範圍內,但加上之前的加總大於最大限制→爆掉回傳OverLargest
4.頭尾加起來在範圍內,但加上之前的加總小於最小限制→爆掉回傳OverLowest
5.頭尾加起來在範圍內,加上之前的加總在範圍內→更新加總、頭向後移、尾向前移,再跑一次檢查這五種情形
6.一直到最後都沒超出範圍→回傳加總
*/
if(head < tail - 1) //判斷是不是指到同一元素
{
if((numeric_limits<Type>::max() / 2) - (v[head] / 2) < (v[tail - 1] / 2)) //第1種情形
//要把每個都除以2的原因,是為了避免head是負數,結果一被最大值減下去就爆掉。然後為了方便,不管哪種都除以2這樣
throw OverLargest();
if((-numeric_limits<Type>::max() / 2) - (v[head] / 2) > (v[tail - 1] / 2)) //第2種情形
throw OverLowest();
if((numeric_limits<Type>::max() / 2) - (reg / 2) < (v[head] / 2) + (v[tail - 1] / 2)) //第3種情形
throw OverLargest();
if((-numeric_limits<Type>::max() / 2) - (reg / 2) > (v[head] / 2) + (v[tail - 1] / 2)) //第4種情形
throw OverLowest();
reg = reg + v[head] + v[tail-1]; //第5種情形
}
else //頭尾指到同一元素時,為避免多加一次,必須另外處理。由於該元素範圍一定在該型態的最大最小值之間,因此不需要檢測第1第2種情形
{
if((numeric_limits<Type>::max() / 2) - (reg / 2) < (v[head] / 2)) //第3種情形
throw OverLargest();
if((-numeric_limits<Type>::max() / 2) - (reg / 2) > (v[head] / 2)) //第4種情形
throw OverLowest();
reg = reg + v[head]; //第5種情形
}
//第5種情形
head++;
tail--;
}
//第6種情形
return reg;
}
else //unsigned數的處理方法,只要一直往後加,判斷有沒有爆炸就好
{
for(int head = 0; head < tail; head++)
{
if((numeric_limits<Type>::max() / 2) - (reg / 2) < (v[head] / 2))
/*
不能寫"reg + vec[head] > numeric_limits<Type>::max()",因為如果左邊已經爆掉了,那會產生無法預知的結果
也不能寫"reg - numeric_limits<Type>::max() + vec[head] > 0",因為reg不是小於就是等於型態最大值,減出來結果不是負數就是0
但unsigned型態不會有負數,會造成大災難
*/
throw OverLargest();
else
reg += v[head];
}
return reg; //一直都沒有爆掉的話就回傳
}
};
};
template<typename Type>
ostream& operator<<(ostream& ostr, const vectorX<Type>& v)
{
for(int i = 0; i < v.size(); i++)
ostr << v[i] << ", ";
return ostr;
};
// Exception classes
class OverLargest
{
public:
string message()
{
return string("largest overflow");
};
};
class OverLowest
{
public:
string message()
{
return string("lowest overflow");
};
};
#endif