Guest User

Untitled

a guest
Jan 19th, 2019
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.11 KB | None | 0 0
  1. template<class I, class F> I closest_int(F f)
  2. {
  3. return I(f);
  4. }
  5.  
  6. template<class I, class F> I closest_int(F f)
  7. {
  8. if (f < std::numeric_limits<I>::min()) return std::numeric_limits<I>::min();
  9. if (std::numeric_limits<I>::max() < f) return std::numeric_limits<I>::max();
  10. return I(f);
  11. }
  12.  
  13. template<class I, class F> I closest_int(F f)
  14. {
  15. if (f <= std::numeric_limits<I>::min()) return std::numeric_limits<I>::min();
  16. if (std::numeric_limits<I>::max() <= f) return std::numeric_limits<I>::max();
  17. return I(f);
  18. }
  19.  
  20. // file: f2i.cpp
  21. //
  22. // compiled with MinGW x86 (gcc version 4.6.2) as:
  23. // g++ -Wall -O2 -std=c++03 f2i.cpp -o f2i.exe
  24. #include <iostream>
  25. #include <iomanip>
  26. #include <limits>
  27.  
  28. using namespace std;
  29.  
  30. template<class I, class F> I truncAndCap(F f)
  31. {
  32. /*
  33. This function converts (by truncating the
  34. fractional part) the floating-point value f (of type F)
  35. into an integer value (of type I), avoiding undefined
  36. behavior by returning std::numeric_limits<I>::min() and
  37. std::numeric_limits<I>::max() when f is too small or
  38. too big to be converted to type I directly.
  39.  
  40. 2 problems:
  41. - F may fail to convert to I,
  42. which is undefined behavior and we want to avoid that.
  43. - I may not convert exactly into F
  44. - Direct I & F comparison fails because of I to F promotion,
  45. which can be inexact.
  46.  
  47. This solution is for the most practical case when I and F
  48. are radix-2 (binary) integer and floating-point types.
  49. */
  50. int Idigits = numeric_limits<I>::digits;
  51. int Isigned = numeric_limits<I>::is_signed;
  52.  
  53. /*
  54. Calculate cutOffMax = 2 ^ std::numeric_limits<I>::digits
  55. (where ^ denotes exponentiation) as a value of type F.
  56.  
  57. We assume that F is a radix-2 (binary) floating-point type AND
  58. it has a big enough exponent part to hold the value of
  59. std::numeric_limits<I>::digits.
  60.  
  61. FLT_MAX_10_EXP/DBL_MAX_10_EXP/LDBL_MAX_10_EXP >= 37
  62. (guaranteed per C++ standard from 2003/C standard from 1999)
  63. corresponds to log2(1e37) ~= 122, so the type I can contain
  64. up to 122 bits. In practice, integers longer than 64 bits
  65. are extremely rare (if existent at all), especially on old systems
  66. of the 2003 C++ standard's time.
  67. */
  68. const F cutOffMax = F(I(1) << Idigits / 2) * F(I(1) << (Idigits / 2 + Idigits % 2));
  69.  
  70. if (f >= cutOffMax)
  71. return numeric_limits<I>::max();
  72.  
  73. /*
  74. Calculate cutOffMin = - 2 ^ std::numeric_limits<I>::digits
  75. (where ^ denotes exponentiation) as a value of type F for
  76. signed I's OR cutOffMin = 0 for unsigned I's in a similar fashion.
  77. */
  78. const F cutOffMin = Isigned ? -F(I(1) << Idigits / 2) * F(I(1) << (Idigits / 2 + Idigits % 2)) : 0;
  79.  
  80. if (f <= cutOffMin)
  81. return numeric_limits<I>::min();
  82.  
  83. /*
  84. Mathematically, we may still have a little problem (2 cases):
  85. cutOffMin < f < std::numeric_limits<I>::min()
  86. srd::numeric_limits<I>::max() < f < cutOffMax
  87.  
  88. These cases are only possible when f isn't a whole number, when
  89. it's either std::numeric_limits<I>::min() - value in the range (0,1)
  90. or std::numeric_limits<I>::max() + value in the range (0,1).
  91.  
  92. We can ignore this altogether because converting f to type I is
  93. guaranteed to truncate the fractional part off, and therefore
  94. I(f) will always be in the range
  95. [std::numeric_limits<I>::min(), std::numeric_limits<I>::max()].
  96. */
  97.  
  98. return I(f);
  99. }
  100.  
  101. template<class I, class F> void test(const char* msg, F f)
  102. {
  103. I i = truncAndCap<I,F>(f);
  104. cout <<
  105. msg <<
  106. setiosflags(ios_base::showpos) <<
  107. setw(14) << setprecision(12) <<
  108. f << " -> " <<
  109. i <<
  110. resetiosflags(ios_base::showpos) <<
  111. endl;
  112. }
  113.  
  114. #define TEST(I,F,VAL)
  115. test<I,F>(#F " -> " #I ": ", VAL);
  116.  
  117. int main()
  118. {
  119. TEST(short, float, -1.75f);
  120. TEST(short, float, -1.25f);
  121. TEST(short, float, +0.00f);
  122. TEST(short, float, +1.25f);
  123. TEST(short, float, +1.75f);
  124.  
  125. TEST(short, float, -32769.00f);
  126. TEST(short, float, -32768.50f);
  127. TEST(short, float, -32768.00f);
  128. TEST(short, float, -32767.75f);
  129. TEST(short, float, -32767.25f);
  130. TEST(short, float, -32767.00f);
  131. TEST(short, float, -32766.00f);
  132. TEST(short, float, +32766.00f);
  133. TEST(short, float, +32767.00f);
  134. TEST(short, float, +32767.25f);
  135. TEST(short, float, +32767.75f);
  136. TEST(short, float, +32768.00f);
  137. TEST(short, float, +32768.50f);
  138. TEST(short, float, +32769.00f);
  139.  
  140. TEST(int, float, -2147483904.00f);
  141. TEST(int, float, -2147483648.00f);
  142. TEST(int, float, -16777218.00f);
  143. TEST(int, float, -16777216.00f);
  144. TEST(int, float, -16777215.00f);
  145. TEST(int, float, +16777215.00f);
  146. TEST(int, float, +16777216.00f);
  147. TEST(int, float, +16777218.00f);
  148. TEST(int, float, +2147483648.00f);
  149. TEST(int, float, +2147483904.00f);
  150.  
  151. TEST(int, double, -2147483649.00);
  152. TEST(int, double, -2147483648.00);
  153. TEST(int, double, -2147483647.75);
  154. TEST(int, double, -2147483647.25);
  155. TEST(int, double, -2147483647.00);
  156. TEST(int, double, +2147483647.00);
  157. TEST(int, double, +2147483647.25);
  158. TEST(int, double, +2147483647.75);
  159. TEST(int, double, +2147483648.00);
  160. TEST(int, double, +2147483649.00);
  161.  
  162. TEST(unsigned, double, -1.00);
  163. TEST(unsigned, double, +1.00);
  164. TEST(unsigned, double, +4294967295.00);
  165. TEST(unsigned, double, +4294967295.25);
  166. TEST(unsigned, double, +4294967295.75);
  167. TEST(unsigned, double, +4294967296.00);
  168. TEST(unsigned, double, +4294967297.00);
  169.  
  170. return 0;
  171. }
  172.  
  173. float -> short: -1.75 -> -1
  174. float -> short: -1.25 -> -1
  175. float -> short: +0 -> +0
  176. float -> short: +1.25 -> +1
  177. float -> short: +1.75 -> +1
  178. float -> short: -32769 -> -32768
  179. float -> short: -32768.5 -> -32768
  180. float -> short: -32768 -> -32768
  181. float -> short: -32767.75 -> -32767
  182. float -> short: -32767.25 -> -32767
  183. float -> short: -32767 -> -32767
  184. float -> short: -32766 -> -32766
  185. float -> short: +32766 -> +32766
  186. float -> short: +32767 -> +32767
  187. float -> short: +32767.25 -> +32767
  188. float -> short: +32767.75 -> +32767
  189. float -> short: +32768 -> +32767
  190. float -> short: +32768.5 -> +32767
  191. float -> short: +32769 -> +32767
  192. float -> int: -2147483904 -> -2147483648
  193. float -> int: -2147483648 -> -2147483648
  194. float -> int: -16777218 -> -16777218
  195. float -> int: -16777216 -> -16777216
  196. float -> int: -16777215 -> -16777215
  197. float -> int: +16777215 -> +16777215
  198. float -> int: +16777216 -> +16777216
  199. float -> int: +16777218 -> +16777218
  200. float -> int: +2147483648 -> +2147483647
  201. float -> int: +2147483904 -> +2147483647
  202. double -> int: -2147483649 -> -2147483648
  203. double -> int: -2147483648 -> -2147483648
  204. double -> int: -2147483647.75 -> -2147483647
  205. double -> int: -2147483647.25 -> -2147483647
  206. double -> int: -2147483647 -> -2147483647
  207. double -> int: +2147483647 -> +2147483647
  208. double -> int: +2147483647.25 -> +2147483647
  209. double -> int: +2147483647.75 -> +2147483647
  210. double -> int: +2147483648 -> +2147483647
  211. double -> int: +2147483649 -> +2147483647
  212. double -> unsigned: -1 -> 0
  213. double -> unsigned: +1 -> 1
  214. double -> unsigned: +4294967295 -> 4294967295
  215. double -> unsigned: +4294967295.25 -> 4294967295
  216. double -> unsigned: +4294967295.75 -> 4294967295
  217. double -> unsigned: +4294967296 -> 4294967295
  218. double -> unsigned: +4294967297 -> 4294967295
Add Comment
Please, Sign In to add comment