/****************************************************************************** TrickLibrary extra URR -万能数値型- URR ヘッダファイル Coded by Wraith in May 27, 2006. ******************************************************************************/ // Tab幅を4文字に設定して表示させてください。 /////////////////////////////////////////////////////////////////////////////// // // ■ urr.h // http://tricklib.com/cxx/ex/urr/urr.h // // □ リファレンス・サポートページ // http://tricklib.com/cxx/ex/urr/ // // □ ライセンス情報 // http://tricklib.com/license.htm // #ifndef TRICKLIB_URR_H #define TRICKLIB_URR_H // // ☆他の浮動小数点型との連携コード除去指定マクロ // // コンパイル時に指定するのが面倒な場合は以下のコメント行を(コメントを解 // 除して)有効にしてください。 // //#define URR_DISABLED_FRIEND_FLOAT // // ☆デフォルト浮動小数点型指定マクロ // // コンパイル時に指定するのが面倒な場合は以下のコメント行を編集した上で // (コメントを解除して)有効にしてください。 // //#define URR_DEFAULT_FRIEND_FLOAT float #ifndef URR_DEFAULT_FRIEND_FLOAT #define URR_DEFAULT_FRIEND_FLOAT double #endif // // ☆最適化コード除去指定マクロ // // コンパイル時に指定するのが面倒な場合は以下のコメント行を(コメントを解 // 除して)有効にしてください。 // //#define URR_EJECT_OPT_CODE // // 〆Visual C++ 6.0 での使用時の注意 // // VC6 でも正常に動作することは確認済みなんだけど、VC6 の template や namespace // まわりの挙動はかなりいい加減なんで、複数の urr クラステンプレートのインスタ // ンスは使用しないほうが吉です。(クラスのインスタンスじゃなくて、テンプレート // のインスタンスの話ね。) // // 〆ベースとなる整数型について // // 現状のこのモジュールでは恐らく組み込み型の整数型でしか正常に機能しないと // 思いすが、多少手を入れればユーザ定義の整数型でも正常に機能すると思います。 #include #include #include #if !defined(WITH_TRICKLIB_URR) # define WITH_TRICKLIB_URR #endif // // ★コンパイラ情報による各種自動判別 // // default ... #define URR_TYPENAME typename // Borland ... #if defined(__BORLANDC__) #include # pragma warn -8027 # ifndef URR_STD_OVERFLOW # define URR_STD_OVERFLOW std::string # endif # ifndef URR_STD_UNDERFLOW # define URR_STD_UNDERFLOW std::string # endif # ifndef URR_STD_INVALID_ARGUMENT # define URR_STD_INVALID_ARGUMENT std::string # endif # ifndef URR_STD_RANGE_ERROR # define URR_STD_RANGE_ERROR std::string # endif #endif // CodeWarrior ... #if defined(__MWERKS__) #endif // Microsoft ... #if defined(_MSC_VER) # if _MSC_VER <= 1200 # undef URR_TYPENAME # define URR_TYPENAME # endif typedef signed char int8_t; typedef unsigned char uint8_t; typedef short int int16_t; typedef unsigned short int uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include #endif // gcc/g++ ... #if defined(__GNUC__) #include # ifndef URR_STD_OVERFLOW # define URR_STD_OVERFLOW std::string # endif # ifndef URR_STD_UNDERFLOW # define URR_STD_UNDERFLOW std::string # endif # ifndef URR_STD_INVALID_ARGUMENT # define URR_STD_INVALID_ARGUMENT std::string # endif # ifndef URR_STD_RANGE_ERROR # define URR_STD_RANGE_ERROR std::string # endif #endif #ifndef URR_STD_OVERFLOW #define URR_STD_OVERFLOW std::overflow_error #endif #ifndef URR_STD_UNDERFLOW #define URR_STD_UNDERFLOW std::underflow_error #endif #ifndef URR_STD_INVALID_ARGUMENT #define URR_STD_INVALID_ARGUMENT std::invalid_argument #endif #ifndef URR_STD_RANGE_ERROR #define URR_STD_RANGE_ERROR std::range_error #endif #if !defined(NDEBUG) #define URR_CONCAT_IDENTIFIER_core(X, Y) X##Y #define URR_CONCAT_IDENTIFIER(X, Y) URR_CONCAT_IDENTIFIER_core(X, Y) #define URR_UNIQUE_IDENTIFIER URR_CONCAT_IDENTIFIER(unique_identifier, __LINE__) #define URR_STATIC_ASSERT(X) int URR_UNIQUE_IDENTIFIER[(X) ? 1: -1] #else #define URR_STATIC_ASSERT(X) #endif namespace urr_tools { // // make_unsigned // template class make_unsigned; template<> class make_unsigned { public: typedef uint8_t type; }; template<> class make_unsigned { public: typedef uint16_t type; }; template<> class make_unsigned { public: typedef uint32_t type; }; template<> class make_unsigned { public: typedef uint64_t type; }; } class urr_kernel_base { public: // 幾何平均部のビット長の取得 inline static int get_geo_exponent_size(int double_exponent_size) { if (double_exponent_size < 5) { // (符号ビットを含んだ)二重指数部のビット長が5に満たない場合は幾何平均部が存在しない。 return 0; } else { return double_exponent_size -4; } } }; template::type> class urr_kernel :public urr_kernel_base { // // このクラステンプレートでは負の値は考慮されていません。 // 負の値はこのクラステンプレートの利用側で処理します。 // public: typedef base_int_type urr_int; typedef base_unsigned_int_type urr_unsigned_int; enum { byte_bitsize = 8, data_bit_size = sizeof(urr_int) *byte_bitsize, }; // 指定されたビット範囲の整数抽出 inline static urr_unsigned_int extract_unsigned_int(const urr_int *data, int begin_bit, int extract_bit_size) { // 引数チェック assert(0 <= begin_bit); assert(0 <= extract_bit_size); assert(extract_bit_size <= data_bit_size); assert(begin_bit < data_bit_size); if (0 == extract_bit_size) { return 0; } else { return ((const urr_unsigned_int)(*((const urr_unsigned_int*)data) << begin_bit)) >> (data_bit_size -extract_bit_size); } } // 二重指数部の解析 inline static void aspect_double_exponent(const urr_int *data, urr_int *double_exponent_value, int *double_exponent_size) { // 引数チェック assert(NULL != data); assert(NULL != double_exponent_value); assert(NULL != double_exponent_size); if (*data < 0) { throw URR_STD_INVALID_ARGUMENT("Invalid argument in aspect_double_exponent@URR"); } // 二重指数部の値が1以上かどうかの判定 bool one_and_over = ((const urr_int)((*data) << 1)) < 0; // 二重指数部のビット長 *double_exponent_size = 3; urr_unsigned_int X1 = *data << 2; urr_unsigned_int X2 = *data << 3; if (one_and_over) { // 1以上... while(*double_exponent_size <= data_bit_size && X2 < X1) { X1 = X2; X2 <<= 1; ++*double_exponent_size; } // この時点で *double_exponent_size は data_bit_size を超えることがあるが、これはそーゆーもの。 } else { // 1未満... while(*double_exponent_size <= data_bit_size && X1 < X2) { X1 = X2; X2 <<= 1; ++*double_exponent_size; } // この時点で *double_exponent_size は data_bit_size を超えることがあるが、これはそーゆーもの。 } // 二重指数部の値 if (one_and_over) { // 1以上... if (3 == *double_exponent_size) { *double_exponent_value = 0; } else { assert(4 <= *double_exponent_size); assert((*double_exponent_size -4) < (data_bit_size -1)); *double_exponent_value = 1 << (*double_exponent_size -4); } } else { // 1未満... assert(3 <= *double_exponent_size); assert((*double_exponent_size -3) < (data_bit_size -1)); *double_exponent_value = 1 << (*double_exponent_size -3); *double_exponent_value *= -1; } } // 幾何平均部の解析 inline static void aspect_geo_exponent(const urr_int *data, int double_exponent_size, urr_int *geo_exponent_value, int *geo_exponent_size) { // 引数チェック assert(NULL != data); assert(NULL != geo_exponent_value); assert(NULL != geo_exponent_size); // 幾何平均部のビット長を調べて *geo_exponent_size = get_geo_exponent_size(double_exponent_size); // 幾何平均部となるビット列を抜き出して unsigned int として評価する。 *geo_exponent_value = (urr_int)extract_unsigned_int(data, double_exponent_size, *geo_exponent_size); } // URR指数部の解析 inline static void aspect_urr_exponent(const urr_int *data, urr_int *exponent_value, int *exponent_size) { // 引数チェック assert(NULL != data); assert(NULL != exponent_value); assert(NULL != exponent_size); // 二重指数部の解析 urr_int double_exponent_value; int double_exponent_size; aspect_double_exponent(data, &double_exponent_value, &double_exponent_size); // 幾何平均部の解析 urr_int geo_exponent_value; int geo_exponent_size; aspect_geo_exponent(data, double_exponent_size, &geo_exponent_value, &geo_exponent_size); // まとめ //  ※*exponent_size は、しばしば data_bit_size を超えることがあるが、これはそーゆーもの。 *exponent_value = double_exponent_value +geo_exponent_value; *exponent_size = double_exponent_size +geo_exponent_size; } // URR指数部と仮数部の解析 inline static void aspect_urr(const urr_int *data, urr_int *exponent, urr_unsigned_int *mantissa, int *matissa_size) { // 引数チェック assert(NULL != data); assert(NULL != exponent); assert(NULL != mantissa); // 指数部の取得 int exponent_size; aspect_urr_exponent(data, exponent, &exponent_size); // 仮数部の取得 if (exponent_size < data_bit_size) { *matissa_size = data_bit_size -exponent_size; *mantissa = *(urr_unsigned_int *)data; const urr_unsigned_int and_mask = ((urr_unsigned_int)(~((urr_unsigned_int)0))) >> exponent_size; *mantissa &= and_mask; const urr_unsigned_int or_mask = and_mask +1; *mantissa |= or_mask; } else { *matissa_size = 0; *mantissa = 1; } } // URR指数部の生成 inline static void make_urr_exponent(urr_int exponent_value, urr_int *data, int *exponent_size) { // 引数チェック assert(NULL != data); assert(NULL != exponent_size); // 二重指数部の生成 urr_int abs_exponent_value; int double_exponent_size = 2; if (0 <= exponent_value) { abs_exponent_value = exponent_value; urr_unsigned_int inter_value = abs_exponent_value; #if !defined(URR_EJECT_OPT_CODE) while(0x3F < inter_value) { assert(double_exponent_size < data_bit_size); double_exponent_size += 6; assert(double_exponent_size < data_bit_size); inter_value >>= 6; } #endif while(double_exponent_size < data_bit_size && 0 < inter_value) { ++double_exponent_size; inter_value >>= 1; } *data = ((urr_unsigned_int)((~((urr_unsigned_int)0)) << (data_bit_size -(double_exponent_size -1)))) >>1; ++double_exponent_size; // この時点で double_exponent_size は data_bit_size を超えることがあるが、これはそーゆーもの。 } else { abs_exponent_value = -exponent_value; urr_unsigned_int inter_value = abs_exponent_value; #if !defined(URR_EJECT_OPT_CODE) while(0x7F < inter_value) { assert(double_exponent_size < data_bit_size); double_exponent_size += 6; assert(double_exponent_size < data_bit_size); inter_value >>= 6; } #endif while(double_exponent_size < data_bit_size && 1 < inter_value) { ++double_exponent_size; inter_value >>= 1; } ++double_exponent_size; if (double_exponent_size <= data_bit_size) { *data = ((urr_unsigned_int)1) << (data_bit_size -double_exponent_size); } else { *data = 0; } // この時点で double_exponent_size は data_bit_size を超えることがあるが、これはそーゆーもの。 } // 幾何平均部の生成 const int geo_exponent_size = get_geo_exponent_size(double_exponent_size); bit_copy(&abs_exponent_value, data_bit_size -geo_exponent_size, data, double_exponent_size); *exponent_size = double_exponent_size +geo_exponent_size; } // URRの生成 // この mantissa は暗黙の1を含まない。 inline static void make_urr(urr_int exponent_value, const urr_unsigned_int *mantissa, urr_int *data) { // 引数チェック assert(NULL != mantissa); assert(NULL != data); // URR指数部の生成 int exponent_size; make_urr_exponent(exponent_value, data, &exponent_size); // 仮数部のコピー if (exponent_size < data_bit_size) { bit_copy(mantissa, 0, data, exponent_size); } } // 指定されたビット位置以降の範囲をクリア inline static void bit_clear(urr_unsigned_int *data, int clear_bit_pos) { //引数チェック assert(NULL != data); assert(0 <= clear_bit_pos); int shift_value = data_bit_size -clear_bit_pos; if (0 < shift_value) { *data &= ((urr_unsigned_int)(urr_int)(-1)) << shift_value; } } // ビットコピー inline static void bit_copy(const urr_unsigned_int *src, int src_bit_pos, urr_unsigned_int *dest, int dest_bit_pos) { // 引数チェック assert(NULL != src); assert(0 <= src_bit_pos); assert(NULL != dest); assert(0 <= dest_bit_pos); if (data_bit_size <= src_bit_pos) { // コピー元のデータが無い return; } if (data_bit_size <= dest_bit_pos) { // コピー先のバッファが無い return; } bit_clear(dest, dest_bit_pos); *dest |= ((urr_unsigned_int)(*src << src_bit_pos)) >> dest_bit_pos; } inline static void bit_copy(const void *src, int src_bit_pos, void *dest, int dest_bit_pos) { bit_copy((const urr_unsigned_int *)src, src_bit_pos, (urr_unsigned_int *)dest, dest_bit_pos); } }; #if !defined(URR_DISABLED_FRIEND_FLOAT) template::type, class friend_float_type = URR_DEFAULT_FRIEND_FLOAT> #else template::type> #endif class urr { public: typedef urr this_type; typedef base_int_type value_type; typedef base_int_type urr_int; typedef base_unsigned_int_type urr_unsigned_int; typedef urr_kernel kernel; enum { byte_bitsize = kernel::byte_bitsize, bit_size = sizeof(base_int_type) *byte_bitsize, }; protected: value_type value; this_type & set_value(value_type X_value) { value = X_value; return *this; } public: urr() :value(0) { URR_STATIC_ASSERT(sizeof(base_int_type) == sizeof(base_unsigned_int_type)); } urr(const this_type &X) { value = X.value; } explicit urr(value_type X_value) { *this = X_value; } #if !defined(URR_DISABLED_FRIEND_FLOAT) explicit urr(friend_float_type X_value) { *this = X_value; } #endif bool is_negative_infinite() const { return !~value; } operator bool () const { return value; } bool operator ! () const { return !value; } this_type operator ~ () const { return this_type().set_value(~value); } this_type operator - () const { return this_type().set_value(-value); } this_type & primary_inc() { ++value; return *this; } this_type & primary_dec() { --value; return *this; } this_type & operator = (this_type X) { return set_value(X.value); } this_type & operator = (value_type X_value) { if (0 == X_value) { value = 0; return *this; } if (X_value < 0) { *this = -this_type((value_type)-X_value); return *this; } assert(0 < X_value); urr_unsigned_int X = X_value; urr_unsigned_int pre_X; urr_int count = 0; #if !defined(URR_EJECT_OPT_CODE) while(X < (~((urr_unsigned_int)(0)) >> 6)) { X <<= 6; count += 6; } #endif do { pre_X = X; X <<= 1; ++count; } while(pre_X < X); kernel::make_urr(bit_size -count, &X, &value); return *this; } #if !defined(URR_DISABLED_FRIEND_FLOAT) this_type & operator = (friend_float_type X_value) { if (0.0 == X_value) { value = 0; return *this; } if (X_value < 0.0) { *this = -this_type(-X_value); return *this; } assert(0.0 < X_value); friend_float_type X = X_value; urr_int exponent_value = 0; urr_unsigned_int mantissa = 0; if (1.0 != X_value) { if (1.0 < X_value) { #if !defined(URR_EJECT_OPT_CODE) while(32.0 <= X) { X /= 32.0; exponent_value += 5; } #endif while(2.0 <= X) { X /= 2.0; ++exponent_value; } } else { #if !defined(URR_EJECT_OPT_CODE) while(X < (1.0 /32.0)) { X *= 32.0; exponent_value -= 5; } #endif while(X < 1.0) { X *= 2.0; --exponent_value; } } assert(1.0 <= X); assert(X < 2.0); X -= 1.0; urr_unsigned_int current_bit = ((urr_unsigned_int)1) << (bit_size -1); while(current_bit && 0.0 < X) { X *= 2.0; if (1.0 <= X) { X -= 1.0; mantissa |= current_bit; } current_bit >>= 1; } } kernel::make_urr(exponent_value, &mantissa, &value); return *this; } #endif operator value_type () const { if (value < 0) { if (is_negative_infinite()) { throw URR_STD_RANGE_ERROR("Negative Infinite in operator value_type()@URR"); //return (value_type)~(urr_unsigned_int)(0); } return -(value_type)-*this; } if (0 == value) { return 0; } urr_int exponent_value; int exponent_size; assert(0 < value); kernel::aspect_urr_exponent(&value, &exponent_value, &exponent_size); if (exponent_value < 0) { // underflow //throw URR_STD_UNDERFLOW("Underflow in operator value_type()@URR"); return 0; } if ((bit_size -1) <= exponent_value) { // overflow //throw URR_STD_OVERFLOW("Overflow in operator value_type()@URR"); return (value_type)~(((urr_unsigned_int)1) << (bit_size -1)); } value_type result = 1; result <<= exponent_value; kernel::bit_copy(&value, exponent_size, &result, bit_size -exponent_value); return result; } #if !defined(URR_DISABLED_FRIEND_FLOAT) operator friend_float_type () const { if (value < 0) { if (is_negative_infinite()) { throw URR_STD_RANGE_ERROR("Negative Infinite in operator friend_float_type()@URR"); } return -*this; } if (0 == value) { return 0; } urr_int exponent_value; int exponent_size; assert(0 < value); kernel::aspect_urr_exponent(&value, &exponent_value, &exponent_size); urr_unsigned_int mantissa = 1; mantissa <<= bit_size -exponent_size; bit_copy(&value, exponent_size, &mantissa, exponent_size); friend_float_type result = mantissa; exponent_value -= bit_size -exponent_size; if (exponent_value) { if (0 < exponent_value) { #if !defined(URR_EJECT_OPT_CODE) while(5 <= exponent_value) { result *= 32.0; exponent_value -= 5; } #endif while(exponent_value) { result *= 2.0; --exponent_value; } } else { #if !defined(URR_EJECT_OPT_CODE) while(exponent_value <= -5) { result /= 32.0; exponent_value += 5; } #endif while(exponent_value) { result /= 2.0; ++exponent_value; } } } return result; } #endif this_type & operator += (const this_type &X) { return *this = *this +X; } this_type & operator -= (const this_type &X) { return *this = *this -X; } this_type & operator *= (const this_type &X) { return *this = *this *X; } this_type & operator /= (const this_type &X) { return *this = *this /X; } friend this_type operator + (const this_type &X, const this_type &Y) { if (X.is_negative_infinite()) { return X; } if (Y.is_negative_infinite()) { return Y; } if (0 == X.value) { return Y; } if (0 == Y.value) { return X; } if (X.value == -(Y.value)) { return this_type(); } // Xの解析 const bool X_is_negative = X.value < 0; urr_int X_exponent; urr_unsigned_int X_mantissa_value; // 暗黙の1を含む。 int X_mantissa_size; if (!X_is_negative) { assert(0 < X.value); kernel::aspect_urr(&(X.value), &X_exponent, &X_mantissa_value, &X_mantissa_size); } else { const value_type positive_X_value = -(X.value); assert(0 < positive_X_value); kernel::aspect_urr(&positive_X_value, &X_exponent, &X_mantissa_value, &X_mantissa_size); } X_exponent -= X_mantissa_size; // Yの解析 const bool Y_is_negative = Y.value < 0; urr_int Y_exponent; urr_unsigned_int Y_mantissa_value; // 暗黙の1を含む。 int Y_mantissa_size; if (!Y_is_negative) { assert(0 < Y.value); kernel::aspect_urr(&(Y.value), &Y_exponent, &Y_mantissa_value, &Y_mantissa_size); } else { const value_type positive_Y_value = -(Y.value); assert(0 < positive_Y_value); kernel::aspect_urr(&positive_Y_value, &Y_exponent, &Y_mantissa_value, &Y_mantissa_size); } Y_exponent -= Y_mantissa_size; if (X_exponent != Y_exponent) { if (X_exponent < Y_exponent) { if (X_exponent +bit_size <= Y_exponent) { return Y; } else { X_mantissa_value >>= (Y_exponent -X_exponent); X_exponent = Y_exponent; } } else { if (Y_exponent +bit_size <= X_exponent) { return X; } else { Y_mantissa_value >>= (X_exponent -Y_exponent); Y_exponent = X_exponent; } } } if (X_is_negative) { X_mantissa_value = (urr_unsigned_int)(-((urr_int)X_mantissa_value)); } if (Y_is_negative) { Y_mantissa_value = (urr_unsigned_int)(-((urr_int)Y_mantissa_value)); } urr_unsigned_int result_mantissa = X_mantissa_value +Y_mantissa_value; if (!result_mantissa) { return this_type(); } const bool result_is_negative = ((urr_int)result_mantissa) < 0; this_type result; urr_unsigned_int rm = (!result_is_negative) ? result_mantissa: -result_mantissa; assert(0 < rm); urr_unsigned_int pre_rm; int count = 0; #if !defined(URR_EJECT_OPT_CODE) while(rm < (~((urr_unsigned_int)(0)) >> 6)) { rm <<= 6; count += 6; } #endif do { pre_rm = rm; rm <<= 1; ++count; } while(pre_rm < rm); X_exponent += bit_size -count; kernel::make_urr(X_exponent, &rm, &(result.value)); if (!result_is_negative) { return result; } else { return -result; } } friend this_type operator - (const this_type &X, const this_type &Y) { return X +(-Y); } friend this_type operator * (const this_type &X, const this_type &Y) { // 特殊ケースを最初に処理 if (X.is_negative_infinite()) { if (Y.value < 0) { throw URR_STD_OVERFLOW("Overflow in operator*(urr, urr)@URR"); } if (Y.value == 0) { throw URR_STD_RANGE_ERROR("Nan in operator*(urr, urr)@URR"); } return X; } if (Y.is_negative_infinite()) { if (X.value < 0) { throw URR_STD_OVERFLOW("Overflow in operator*(urr, urr)@URR"); } if (X.value == 0) { throw URR_STD_RANGE_ERROR("Nan in operator*(urr, urr)@URR"); } return Y; } if (0 == X.value) { return X; } if (0 == Y.value) { return Y; } // Xの解析 const bool X_is_negative = X.value < 0; urr_int X_exponent; urr_unsigned_int X_mantissa_value; // 暗黙の1を含む。 int X_mantissa_size; if (!X_is_negative) { kernel::aspect_urr(&(X.value), &X_exponent, &X_mantissa_value, &X_mantissa_size); } else { const value_type positive_X_value = -(X.value); kernel::aspect_urr(&positive_X_value, &X_exponent, &X_mantissa_value, &X_mantissa_size); } // Yの解析 const bool Y_is_negative = Y.value < 0; urr_int Y_exponent; urr_unsigned_int Y_mantissa_value; // 暗黙の1を含む。 int Y_mantissa_size; if (!Y_is_negative) { kernel::aspect_urr(&(Y.value), &Y_exponent, &Y_mantissa_value, &Y_mantissa_size); } else { const value_type positive_Y_value = -(Y.value); kernel::aspect_urr(&positive_Y_value, &Y_exponent, &Y_mantissa_value, &Y_mantissa_size); } // 指数同士を加算 urr_int result_exponent = X_exponent +Y_exponent; // Xの仮数部を左詰めにする(暗黙の1は残す) assert(0 != X_mantissa_value); urr_unsigned_int A = X_mantissa_value << (bit_size -(X_mantissa_size +1)); // Yの仮数部を左詰めにする(暗黙の1は残す) assert(0 != Y_mantissa_value); urr_unsigned_int B = Y_mantissa_value << (bit_size -(Y_mantissa_size +1)); #if 1 // 仮数部の積算(intベースの積算が高速に行える環境下で高速に動作するアルゴリズム) const int half_size = bit_size /2; urr_unsigned_int A1 = A >>half_size; urr_unsigned_int A2 = A &((~((urr_unsigned_int)0)) >>half_size); urr_unsigned_int B1 = B >> (bit_size /2); urr_unsigned_int B2 = B &((~((urr_unsigned_int)0)) >>half_size); urr_unsigned_int A1B1 = A1 *B1; urr_unsigned_int A1B2 = A1 *B2; urr_unsigned_int A2B1 = A2 *B1; urr_unsigned_int A2B2 = A2 *B2; urr_unsigned_int C = A1B1 +((A1B2 +A2B1 +(A2B2 >>half_size)) >>half_size); #else // 仮数部の積算(intベースの積算が高速に行えない環境向けのアルゴリズム) B >>= 1; urr_unsigned_int C = 0; #if !defined(URR_EJECT_OPT_CODE) while(0 == (A &(urr_unsigned_int)(0x3F))) { A >>= 6; } #endif while(A) { if (A &(urr_unsigned_int)(0x01)) { C += B; } A >>= 1; C >>= 1; } C <<= 1; #endif // 仮数部の暗黙の1を消す urr_unsigned_int result_mantissa = C; if ((result_mantissa <<= 1) < C) { // 積算の結果、仮数部の桁が増えてる。 ++result_exponent; } else { result_mantissa <<= 1; assert(result_mantissa < (C <<1)); } // まとめ this_type result; kernel::make_urr(result_exponent, &result_mantissa, &(result.value)); if (X_is_negative ^Y_is_negative) { return -result; } else { return result; } } friend this_type operator / (const this_type &X, const this_type &Y) { // 特殊ケースを最初に処理 if (value_type(0) == Y.value) { throw URR_STD_RANGE_ERROR("Divide by Zero in operator/(urr, urr)@URR"); } if (0 == X.value) { return X; // == 0 } if (X.is_negative_infinite()) { if (Y.value < 0) { throw URR_STD_OVERFLOW("Overflow in operator/(urr, urr)@URR"); } if (Y.is_negative_infinite()) { throw URR_STD_RANGE_ERROR("Nan in operator/(urr, urr)@URR"); } return X; // == negative infinite } if (Y.is_negative_infinite()) { return this_type(); // this_type() means zero. } // Xの解析 const bool X_is_negative = X.value < 0; urr_int X_exponent; urr_unsigned_int X_mantissa_value; // 暗黙の1を含む。 int X_mantissa_size; if (!X_is_negative) { kernel::aspect_urr(&(X.value), &X_exponent, &X_mantissa_value, &X_mantissa_size); } else { const value_type positive_X_value = -X.value; kernel::aspect_urr(&positive_X_value, &X_exponent, &X_mantissa_value, &X_mantissa_size); } // Yの解析 const bool Y_is_negative = Y.value < 0; urr_int Y_exponent; urr_unsigned_int Y_mantissa_value; // 暗黙の1を含む。 int Y_mantissa_size; if (!Y_is_negative) { kernel::aspect_urr(&(Y.value), &Y_exponent, &Y_mantissa_value, &Y_mantissa_size); } else { const value_type positive_Y_value = -Y.value; kernel::aspect_urr(&positive_Y_value, &Y_exponent, &Y_mantissa_value, &Y_mantissa_size); } // 指数同士を減算 urr_int result_exponent = X_exponent -Y_exponent; // Xの仮数部を(暗黙の1を保ったまま)左詰めにする assert(0 != X_mantissa_value); urr_unsigned_int A = X_mantissa_value << (bit_size -(X_mantissa_size +1)); // Yの仮数部を(暗黙の1を保ったまま)左詰めにする assert(0 != Y_mantissa_value); urr_unsigned_int B = Y_mantissa_value << (bit_size -(Y_mantissa_size +1)); // overflowを起こさないようにする為 A および B を1ビット右にシフトしておく。 // (仮数部の有効桁数は暗黙の1を含めても最大で bit_size -2 なので、このシフトで桁落ちするビットは発生しない) A >>= 1; B >>= 1; #if 0 // 仮数部の除算(intベースの除算が高速に行える環境下で高速に動作するアルゴリズム) 積算と同様のやり方でうまくいけばいいんだけど、計算精度が悪くなりそうなのと 結構ごっちゃりとした処理になりそうなんで今回は見送り。 # 倍の精度の整数型を利用すれば、ちょろそうだけど。 #else // 仮数部の除算(intベースの除算が高速に行えない環境向けのアルゴリズム) urr_unsigned_int C = 0; urr_unsigned_int weight = ~(urr_unsigned_int)(((urr_unsigned_int)~urr_unsigned_int(0)) >> 1); do { if (B <= A) { C |= weight; A -= B; if (!A) { break; } } assert(A); assert(A < (A << 1)); A <<= 1; weight >>= 1; } while(weight); #endif // 仮数部の暗黙の1を消す urr_unsigned_int result_mantissa = C; if (C < (result_mantissa <<= 1)) { // 除算の結果、仮数部が1未満になっている。 assert((urr_unsigned_int)(result_mantissa <<1) < result_mantissa); --result_exponent; result_mantissa <<= 1; } // まとめ this_type result; kernel::make_urr(result_exponent, &result_mantissa, &(result.value)); if (X_is_negative ^Y_is_negative) { return -result; } else { return result; } } friend inline bool operator == (const this_type &X, const this_type &Y) { return X.value == Y.value; } friend inline bool operator != (const this_type &X, const this_type &Y) { return X.value != Y.value; } friend inline bool operator < (const this_type &X, const this_type &Y) { return X.value < Y.value; } friend inline bool operator <= (const this_type &X, const this_type &Y) { return X.value <= Y.value; } friend inline bool operator > (const this_type &X, const this_type &Y) { return X.value > Y.value; } friend inline bool operator >= (const this_type &X, const this_type &Y) { return X.value >= Y.value; } friend inline bool operator == (const value_type &X, const this_type &Y) { return this_type(X).value == Y.value; } friend inline bool operator != (const value_type &X, const this_type &Y) { return this_type(X).value != Y.value; } friend inline bool operator < (const value_type &X, const this_type &Y) { return this_type(X).value < Y.value; } friend inline bool operator <= (const value_type &X, const this_type &Y) { return this_type(X).value <= Y.value; } friend inline bool operator > (const value_type &X, const this_type &Y) { return this_type(X).value > Y.value; } friend inline bool operator >= (const value_type &X, const this_type &Y) { return this_type(X).value >= Y.value; } friend inline bool operator == (const this_type &X, const value_type &Y) { return X.value == this_type(Y).value; } friend inline bool operator != (const this_type &X, const value_type &Y) { return X.value != this_type(Y).value; } friend inline bool operator < (const this_type &X, const value_type &Y) { return X.value < this_type(Y).value; } friend inline bool operator <= (const this_type &X, const value_type &Y) { return X.value <= this_type(Y).value; } friend inline bool operator > (const this_type &X, const value_type &Y) { return X.value > this_type(Y).value; } friend inline bool operator >= (const this_type &X, const value_type &Y) { return X.value >= this_type(Y).value; } #if !defined(URR_DISABLED_FRIEND_FLOAT) friend inline bool operator == (const friend_float_type &X, const this_type &Y) { return this_type(X).value == Y.value; } friend inline bool operator != (const friend_float_type &X, const this_type &Y) { return this_type(X).value != Y.value; } friend inline bool operator < (const friend_float_type &X, const this_type &Y) { return this_type(X).value < Y.value; } friend inline bool operator <= (const friend_float_type &X, const this_type &Y) { return this_type(X).value <= Y.value; } friend inline bool operator > (const friend_float_type &X, const this_type &Y) { return this_type(X).value > Y.value; } friend inline bool operator >= (const friend_float_type &X, const this_type &Y) { return this_type(X).value >= Y.value; } friend inline bool operator == (const this_type &X, const friend_float_type &Y) { return X.value == this_type(Y).value; } friend inline bool operator != (const this_type &X, const friend_float_type &Y) { return X.value != this_type(Y).value; } friend inline bool operator < (const this_type &X, const friend_float_type &Y) { return X.value < this_type(Y).value; } friend inline bool operator <= (const this_type &X, const friend_float_type &Y) { return X.value <= this_type(Y).value; } friend inline bool operator > (const this_type &X, const friend_float_type &Y) { return X.value > this_type(Y).value; } friend inline bool operator >= (const this_type &X, const friend_float_type &Y) { return X.value >= this_type(Y).value; } #endif }; #if defined(__BORLANDC__) # pragma warn .8027 #endif #endif // TRICKLIB_URR_H /****************************************************************************** □■□■ Wraith the Trickster □■□■ ■□■□ 〜I'll go with heaven's advantage and fool's wisdom.〜 ■□■□ ******************************************************************************/