SHARE
TWEET

Untitled

a guest Jan 19th, 2019 52 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top