fork download
  1. namespace h3d {
  2. /**
  3. * 許容誤差クラス。
  4. * double型では、比較する二つの数の指数部と1023のうち最大のものをxとすると、
  5. * 許容誤差は 2^(x - 精度 - 1023) となる。
  6. * @param F 浮動小数点数(Floating-point number)の型。
  7. */
  8. template<typename F>
  9. class AllowableLimit {
  10. public:
  11. /** 精度(PreCiSion)。 */
  12. static int pcs;
  13.  
  14. /**
  15. * 浮動小数点数の指数部を取得する。
  16. * @param num 数(NUMber)。
  17. * @return 取得した指数部。
  18. */
  19. inline static int exponent(const F& num);
  20.  
  21. /**
  22. * 二つの浮動小数点数の許容誤差を作る。
  23. * @param lhs 左側(Left Hand Side)の数。
  24. * @param rhs 右側(Right Hand Side)の数。
  25. * @return 作った許容誤差。
  26. */
  27. inline static F make(const F& lhs, const F& rhs);
  28. };
  29.  
  30. /**
  31. * 二つの数が近いかどうかを判定する。
  32. * @param X 数の型。
  33. * @param lhs 左側(Left Hand Side)の数。
  34. * @param rhs 右側(Right Hand Side)の数。
  35. * @return 近いならtrue, 遠いならfalse。
  36. */
  37. template<typename X>
  38. inline bool nearEqual(const X& lhs, const X& rhs);
  39. };
  40.  
  41. #include <iomanip>
  42. #include <iostream>
  43. #include <string>
  44.  
  45. #define ASSERT(pred) h3d::assert(#pred, (pred));
  46.  
  47. #define PRINT(val) cout << #val << "=" << (val) << endl;
  48.  
  49. namespace h3d {
  50. using std::cout;
  51. using std::dec;
  52. using std::endl;
  53. using std::hex;
  54. using std::setfill;
  55. using std::setw;
  56. using std::setprecision;
  57. using std::string;
  58.  
  59. /**
  60. * アサーションを実行する。
  61. * 成功なら標準出力に結果を出力する。
  62. * @param pred_str 判定する述語(PREDicate)を記述した文字列(STRing)。
  63. * @param pred_res 判定する述語(PREDicate)の結果(RESult)。
  64. * trueなら成功,falseなら失敗と判定する。
  65. * @throw string 失敗ならメッセージをスローする。
  66. */
  67. inline void assert(const string& pred_str, const bool& pred_res) throw(string);
  68. };
  69.  
  70. ////////////////////////////////////////////////////////////////////////////////
  71.  
  72. #include <algorithm>
  73. #include <cmath>
  74.  
  75. namespace h3d {
  76. using std::fabs;
  77. using std::max;
  78.  
  79. template<>
  80. int AllowableLimit<double>::pcs = 48;
  81.  
  82. template<>
  83. inline int AllowableLimit<double>::exponent(const double& num) {
  84. return (int)(*(unsigned long long*)&num >> 52) & ((1 << 11) - 1);
  85. }
  86.  
  87. template<>
  88. inline double AllowableLimit<double>::make(const double& lhs, const double& rhs) {
  89. unsigned long long alw_lmt = max(max(exponent(lhs), exponent(rhs)), 1023) - pcs;
  90. return *(double*)&(alw_lmt <<= 52);
  91. }
  92.  
  93. template<typename X>
  94. inline bool nearEqual(const X& lhs, const X& rhs) { return lhs == rhs; }
  95.  
  96. template<>
  97. inline bool nearEqual<double>(const double& lhs, const double& rhs) {
  98. return fabs(lhs - rhs) <= AllowableLimit<double>::make(lhs, rhs);
  99. }
  100. };
  101.  
  102. #include <iostream>
  103. #include <string>
  104.  
  105. namespace h3d {
  106. using std::cout;
  107. using std::endl;
  108. using std::string;
  109.  
  110. inline void assert(const string& pred_str, const bool& pred_res) throw(string) {
  111. if (pred_res) cout << "アサート成功: " << pred_str << endl;
  112. else throw "アサート失敗: " + pred_str;
  113. }
  114. };
  115.  
  116. #include <cmath>
  117. #include <cstdio>
  118. #include <iostream>
  119. #include <string>
  120.  
  121. int main() {
  122. try {
  123. double x, y, a;
  124. std::cout << "xとy: 比較する二つの数, d: xとyの差の絶対値, a: 許容誤差" << std::endl;
  125.  
  126. h3d::AllowableLimit<double>::pcs = 48;
  127. std::cout << "許容誤差の精度: " << h3d::AllowableLimit<double>::pcs << std::endl;
  128. std::cout << std::endl;
  129.  
  130. x = 1.000000000000005;
  131. y = 1.000000000000004;
  132. a = h3d::AllowableLimit<double>::make(x, y);
  133. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  134. ASSERT(h3d::nearEqual<double>(x, y) == true)
  135. std::cout << std::endl;
  136.  
  137. x = 1.000000000000050;
  138. y = 1.000000000000040;
  139. a = h3d::AllowableLimit<double>::make(x, y);
  140. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  141. ASSERT(h3d::nearEqual<double>(x, y) == false)
  142. std::cout << std::endl;
  143.  
  144. x = 100000000000000.5;
  145. y = 100000000000000.4;
  146. a = h3d::AllowableLimit<double>::make(x, y);
  147. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  148. ASSERT(h3d::nearEqual<double>(x, y) == true)
  149. std::cout << std::endl;
  150.  
  151. x = 100000000000005.0;
  152. y = 100000000000004.0;
  153. a = h3d::AllowableLimit<double>::make(x, y);
  154. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  155. ASSERT(h3d::nearEqual<double>(x, y) == false)
  156. std::cout << std::endl;
  157.  
  158. x = 0.000000000000005;
  159. y = 0.000000000000004;
  160. a = h3d::AllowableLimit<double>::make(x, y);
  161. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  162. ASSERT(h3d::nearEqual<double>(x, y) == true)
  163. std::cout << std::endl;
  164.  
  165. x = 0.000000000000050;
  166. y = 0.000000000000040;
  167. a = h3d::AllowableLimit<double>::make(x, y);
  168. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  169. ASSERT(h3d::nearEqual<double>(x, y) == false)
  170. std::cout << std::endl;
  171.  
  172. h3d::AllowableLimit<double>::pcs = 46;
  173. std::cout << "許容誤差の精度: " << h3d::AllowableLimit<double>::pcs << std::endl;
  174. std::cout << std::endl;
  175.  
  176. x = 1.000000000000050;
  177. y = 1.000000000000040;
  178. a = h3d::AllowableLimit<double>::make(x, y);
  179. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  180. ASSERT(h3d::nearEqual<double>(x, y) == true)
  181. std::cout << std::endl;
  182.  
  183. x = 1.000000000000500;
  184. y = 1.000000000000400;
  185. a = h3d::AllowableLimit<double>::make(x, y);
  186. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  187. ASSERT(h3d::nearEqual<double>(x, y) == false)
  188. std::cout << std::endl;
  189.  
  190. x = 100000000000005.0;
  191. y = 100000000000004.0;
  192. a = h3d::AllowableLimit<double>::make(x, y);
  193. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  194. ASSERT(h3d::nearEqual<double>(x, y) == true)
  195. std::cout << std::endl;
  196.  
  197. x = 100000000000050.0;
  198. y = 100000000000040.0;
  199. a = h3d::AllowableLimit<double>::make(x, y);
  200. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  201. ASSERT(h3d::nearEqual<double>(x, y) == false)
  202. std::cout << std::endl;
  203.  
  204. x = 0.000000000000050;
  205. y = 0.000000000000040;
  206. a = h3d::AllowableLimit<double>::make(x, y);
  207. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  208. ASSERT(h3d::nearEqual<double>(x, y) == true)
  209. std::cout << std::endl;
  210.  
  211. x = 0.000000000000500;
  212. y = 0.000000000000400;
  213. a = h3d::AllowableLimit<double>::make(x, y);
  214. std::printf("x=%31.15f\ny=%31.15f\nd=%31.15f\na=%31.15f\n", x, y, std::fabs(x - y), a);
  215. ASSERT(h3d::nearEqual<double>(x, y) == false)
  216. std::cout << std::endl;
  217. }
  218. catch (const std::string& msg) {
  219. std::cerr << msg << std::endl;
  220. return 1;
  221. }
  222. return 0;
  223. }
  224.  
Success #stdin #stdout 0s 3476KB
stdin
Standard input is empty
stdout
xとy: 比較する二つの数, d: xとyの差の絶対値, a: 許容誤差
許容誤差の精度: 48

x=              1.000000000000005
y=              1.000000000000004
d=              0.000000000000001
a=              0.000000000000004
アサート成功: h3d::nearEqual<double>(x, y) == true

x=              1.000000000000050
y=              1.000000000000040
d=              0.000000000000010
a=              0.000000000000004
アサート成功: h3d::nearEqual<double>(x, y) == false

x=100000000000000.500000000000000
y=100000000000000.406250000000000
d=              0.093750000000000
a=              0.250000000000000
アサート成功: h3d::nearEqual<double>(x, y) == true

x=100000000000005.000000000000000
y=100000000000004.000000000000000
d=              1.000000000000000
a=              0.250000000000000
アサート成功: h3d::nearEqual<double>(x, y) == false

x=              0.000000000000005
y=              0.000000000000004
d=              0.000000000000001
a=              0.000000000000004
アサート成功: h3d::nearEqual<double>(x, y) == true

x=              0.000000000000050
y=              0.000000000000040
d=              0.000000000000010
a=              0.000000000000004
アサート成功: h3d::nearEqual<double>(x, y) == false

許容誤差の精度: 46

x=              1.000000000000050
y=              1.000000000000040
d=              0.000000000000010
a=              0.000000000000014
アサート成功: h3d::nearEqual<double>(x, y) == true

x=              1.000000000000500
y=              1.000000000000400
d=              0.000000000000100
a=              0.000000000000014
アサート成功: h3d::nearEqual<double>(x, y) == false

x=100000000000005.000000000000000
y=100000000000004.000000000000000
d=              1.000000000000000
a=              1.000000000000000
アサート成功: h3d::nearEqual<double>(x, y) == true

x=100000000000050.000000000000000
y=100000000000040.000000000000000
d=             10.000000000000000
a=              1.000000000000000
アサート成功: h3d::nearEqual<double>(x, y) == false

x=              0.000000000000050
y=              0.000000000000040
d=              0.000000000000010
a=              0.000000000000014
アサート成功: h3d::nearEqual<double>(x, y) == true

x=              0.000000000000500
y=              0.000000000000400
d=              0.000000000000100
a=              0.000000000000014
アサート成功: h3d::nearEqual<double>(x, y) == false