// file: f2i.cpp
//
// compiled with MinGW x86 (gcc version 4.6.2) as:
// g++ -Wall -O2 -std=c++03 f2i.cpp -o f2i.exe
#include <iostream>
#include <iomanip>
#include <limits>
using namespace std;
template<class I, class F> I truncAndCap(F f)
{
/*
This function converts (by truncating the
fractional part) the floating-point value f (of type F)
into an integer value (of type I), avoiding undefined
behavior by returning std::numeric_limits<I>::min() and
std::numeric_limits<I>::max() when f is too small or
too big to be converted to type I directly.
2 problems:
- F may fail to convert to I,
which is undefined behavior and we want to avoid that.
- I may not convert exactly into F
- Direct I & F comparison fails because of I to F promotion,
which can be inexact.
This solution is for the most practical case when I and F
are radix-2 (binary) integer and floating-point types.
*/
int Idigits = numeric_limits<I>::digits;
int Isigned = numeric_limits<I>::is_signed;
/*
Calculate cutOffMax = 2 ^ std::numeric_limits<I>::digits
(where ^ denotes exponentiation) as a value of type F.
We assume that F is a radix-2 (binary) floating-point type AND
it has a big enough exponent part to hold the value of
std::numeric_limits<I>::digits.
FLT_MAX_10_EXP/DBL_MAX_10_EXP/LDBL_MAX_10_EXP >= 37
(guaranteed per C++ standard from 2003/C standard from 1999)
corresponds to log2(1e37) ~= 122, so the type I can contain
up to 122 bits. In practice, integers longer than 64 bits
are extremely rare (if existent at all), especially on old systems
of the 2003 C++ standard's time.
*/
const F cutOffMax = F(I(1) << Idigits / 2) * F(I(1) << (Idigits / 2 + Idigits % 2));
if (f >= cutOffMax)
return numeric_limits<I>::max();
/*
Calculate cutOffMin = - 2 ^ std::numeric_limits<I>::digits
(where ^ denotes exponentiation) as a value of type F for
signed I's OR cutOffMin = 0 for unsigned I's in a similar fashion.
*/
const F cutOffMin = Isigned ? -F(I(1) << Idigits / 2) * F(I(1) << (Idigits / 2 + Idigits % 2)) : 0;
if (f <= cutOffMin)
return numeric_limits<I>::min();
/*
Mathematically, we may still have a little problem (2 cases):
cutOffMin < f < std::numeric_limits<I>::min()
srd::numeric_limits<I>::max() < f < cutOffMax
These cases are only possible when f isn't a whole number, when
it's either std::numeric_limits<I>::min() - value in the range (0,1)
or std::numeric_limits<I>::max() + value in the range (0,1).
We can ignore this altogether because converting f to type I is
guaranteed to truncate the fractional part off, and therefore
I(f) will always be in the range
[std::numeric_limits<I>::min(), std::numeric_limits<I>::max()].
*/
return I(f);
}
template<class I, class F> void test(const char* msg, F f)
{
I i = truncAndCap<I,F>(f);
cout <<
msg <<
setiosflags(ios_base::showpos) <<
setw(14) << setprecision(12) <<
f << " -> " <<
i <<
resetiosflags(ios_base::showpos) <<
endl;
}
#define TEST(I,F,VAL) \
test<I,F>(#F " -> " #I ": ", VAL);
int main()
{
TEST(short, float, -1.75f);
TEST(short, float, -1.25f);
TEST(short, float, +0.00f);
TEST(short, float, +1.25f);
TEST(short, float, +1.75f);
TEST(short, float, -32769.00f);
TEST(short, float, -32768.50f);
TEST(short, float, -32768.00f);
TEST(short, float, -32767.75f);
TEST(short, float, -32767.25f);
TEST(short, float, -32767.00f);
TEST(short, float, -32766.00f);
TEST(short, float, +32766.00f);
TEST(short, float, +32767.00f);
TEST(short, float, +32767.25f);
TEST(short, float, +32767.75f);
TEST(short, float, +32768.00f);
TEST(short, float, +32768.50f);
TEST(short, float, +32769.00f);
TEST(int, float, -2147483904.00f);
TEST(int, float, -2147483648.00f);
TEST(int, float, -16777218.00f);
TEST(int, float, -16777216.00f);
TEST(int, float, -16777215.00f);
TEST(int, float, +16777215.00f);
TEST(int, float, +16777216.00f);
TEST(int, float, +16777218.00f);
TEST(int, float, +2147483648.00f);
TEST(int, float, +2147483904.00f);
TEST(int, double, -2147483649.00);
TEST(int, double, -2147483648.00);
TEST(int, double, -2147483647.75);
TEST(int, double, -2147483647.25);
TEST(int, double, -2147483647.00);
TEST(int, double, +2147483647.00);
TEST(int, double, +2147483647.25);
TEST(int, double, +2147483647.75);
TEST(int, double, +2147483648.00);
TEST(int, double, +2147483649.00);
TEST(unsigned, double, -1.00);
TEST(unsigned, double, +1.00);
TEST(unsigned, double, +4294967295.00);
TEST(unsigned, double, +4294967295.25);
TEST(unsigned, double, +4294967295.75);
TEST(unsigned, double, +4294967296.00);
TEST(unsigned, double, +4294967297.00);
return 0;
}
Ly8gZmlsZTogZjJpLmNwcAovLwovLyBjb21waWxlZCB3aXRoIE1pbkdXIHg4NiAoZ2NjIHZlcnNpb24gNC42LjIpIGFzOgovLyAgIGcrKyAtV2FsbCAtTzIgLXN0ZD1jKyswMyBmMmkuY3BwIC1vIGYyaS5leGUKI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8aW9tYW5pcD4KI2luY2x1ZGUgPGxpbWl0cz4KCnVzaW5nIG5hbWVzcGFjZSBzdGQ7Cgp0ZW1wbGF0ZTxjbGFzcyBJLCBjbGFzcyBGPiBJIHRydW5jQW5kQ2FwKEYgZikKewovKgogIFRoaXMgZnVuY3Rpb24gY29udmVydHMgKGJ5IHRydW5jYXRpbmcgdGhlCiAgZnJhY3Rpb25hbCBwYXJ0KSB0aGUgZmxvYXRpbmctcG9pbnQgdmFsdWUgZiAob2YgdHlwZSBGKQogIGludG8gYW4gaW50ZWdlciB2YWx1ZSAob2YgdHlwZSBJKSwgYXZvaWRpbmcgdW5kZWZpbmVkCiAgYmVoYXZpb3IgYnkgcmV0dXJuaW5nIHN0ZDo6bnVtZXJpY19saW1pdHM8ST46Om1pbigpIGFuZAogIHN0ZDo6bnVtZXJpY19saW1pdHM8ST46Om1heCgpIHdoZW4gZiBpcyB0b28gc21hbGwgb3IKICB0b28gYmlnIHRvIGJlIGNvbnZlcnRlZCB0byB0eXBlIEkgZGlyZWN0bHkuCgogIDIgcHJvYmxlbXM6CiAgLSBGIG1heSBmYWlsIHRvIGNvbnZlcnQgdG8gSSwKICAgIHdoaWNoIGlzIHVuZGVmaW5lZCBiZWhhdmlvciBhbmQgd2Ugd2FudCB0byBhdm9pZCB0aGF0LgogIC0gSSBtYXkgbm90IGNvbnZlcnQgZXhhY3RseSBpbnRvIEYKICAgIC0gRGlyZWN0IEkgJiBGIGNvbXBhcmlzb24gZmFpbHMgYmVjYXVzZSBvZiBJIHRvIEYgcHJvbW90aW9uLAogICAgICB3aGljaCBjYW4gYmUgaW5leGFjdC4KCiAgVGhpcyBzb2x1dGlvbiBpcyBmb3IgdGhlIG1vc3QgcHJhY3RpY2FsIGNhc2Ugd2hlbiBJIGFuZCBGCiAgYXJlIHJhZGl4LTIgKGJpbmFyeSkgaW50ZWdlciBhbmQgZmxvYXRpbmctcG9pbnQgdHlwZXMuCiovCiAgaW50IElkaWdpdHMgPSBudW1lcmljX2xpbWl0czxJPjo6ZGlnaXRzOwogIGludCBJc2lnbmVkID0gbnVtZXJpY19saW1pdHM8ST46OmlzX3NpZ25lZDsKCi8qCiAgQ2FsY3VsYXRlIGN1dE9mZk1heCA9IDIgXiBzdGQ6Om51bWVyaWNfbGltaXRzPEk+OjpkaWdpdHMKICAod2hlcmUgXiBkZW5vdGVzIGV4cG9uZW50aWF0aW9uKSBhcyBhIHZhbHVlIG9mIHR5cGUgRi4KCiAgV2UgYXNzdW1lIHRoYXQgRiBpcyBhIHJhZGl4LTIgKGJpbmFyeSkgZmxvYXRpbmctcG9pbnQgdHlwZSBBTkQKICBpdCBoYXMgYSBiaWcgZW5vdWdoIGV4cG9uZW50IHBhcnQgdG8gaG9sZCB0aGUgdmFsdWUgb2YKICBzdGQ6Om51bWVyaWNfbGltaXRzPEk+OjpkaWdpdHMuCgogIEZMVF9NQVhfMTBfRVhQL0RCTF9NQVhfMTBfRVhQL0xEQkxfTUFYXzEwX0VYUCA+PSAzNwogIChndWFyYW50ZWVkIHBlciBDKysgc3RhbmRhcmQgZnJvbSAyMDAzL0Mgc3RhbmRhcmQgZnJvbSAxOTk5KQogIGNvcnJlc3BvbmRzIHRvIGxvZzIoMWUzNykgfj0gMTIyLCBzbyB0aGUgdHlwZSBJIGNhbiBjb250YWluCiAgdXAgdG8gMTIyIGJpdHMuIEluIHByYWN0aWNlLCBpbnRlZ2VycyBsb25nZXIgdGhhbiA2NCBiaXRzCiAgYXJlIGV4dHJlbWVseSByYXJlIChpZiBleGlzdGVudCBhdCBhbGwpLCBlc3BlY2lhbGx5IG9uIG9sZCBzeXN0ZW1zCiAgb2YgdGhlIDIwMDMgQysrIHN0YW5kYXJkJ3MgdGltZS4KKi8KICBjb25zdCBGIGN1dE9mZk1heCA9IEYoSSgxKSA8PCBJZGlnaXRzIC8gMikgKiBGKEkoMSkgPDwgKElkaWdpdHMgLyAyICsgSWRpZ2l0cyAlIDIpKTsKCiAgaWYgKGYgPj0gY3V0T2ZmTWF4KQogICAgcmV0dXJuIG51bWVyaWNfbGltaXRzPEk+OjptYXgoKTsKCi8qCiAgQ2FsY3VsYXRlIGN1dE9mZk1pbiA9IC0gMiBeIHN0ZDo6bnVtZXJpY19saW1pdHM8ST46OmRpZ2l0cwogICh3aGVyZSBeIGRlbm90ZXMgZXhwb25lbnRpYXRpb24pIGFzIGEgdmFsdWUgb2YgdHlwZSBGIGZvcgogIHNpZ25lZCBJJ3MgT1IgY3V0T2ZmTWluID0gMCBmb3IgdW5zaWduZWQgSSdzIGluIGEgc2ltaWxhciBmYXNoaW9uLgoqLwogIGNvbnN0IEYgY3V0T2ZmTWluID0gSXNpZ25lZCA/IC1GKEkoMSkgPDwgSWRpZ2l0cyAvIDIpICogRihJKDEpIDw8IChJZGlnaXRzIC8gMiArIElkaWdpdHMgJSAyKSkgOiAwOwoKICBpZiAoZiA8PSBjdXRPZmZNaW4pCiAgICByZXR1cm4gbnVtZXJpY19saW1pdHM8ST46Om1pbigpOwoKLyoKICBNYXRoZW1hdGljYWxseSwgd2UgbWF5IHN0aWxsIGhhdmUgYSBsaXR0bGUgcHJvYmxlbSAoMiBjYXNlcyk6CiAgICBjdXRPZmZNaW4gPCBmIDwgc3RkOjpudW1lcmljX2xpbWl0czxJPjo6bWluKCkKICAgIHNyZDo6bnVtZXJpY19saW1pdHM8ST46Om1heCgpIDwgZiA8IGN1dE9mZk1heAoKICBUaGVzZSBjYXNlcyBhcmUgb25seSBwb3NzaWJsZSB3aGVuIGYgaXNuJ3QgYSB3aG9sZSBudW1iZXIsIHdoZW4KICBpdCdzIGVpdGhlciBzdGQ6Om51bWVyaWNfbGltaXRzPEk+OjptaW4oKSAtIHZhbHVlIGluIHRoZSByYW5nZSAoMCwxKQogIG9yIHN0ZDo6bnVtZXJpY19saW1pdHM8ST46Om1heCgpICsgdmFsdWUgaW4gdGhlIHJhbmdlICgwLDEpLgoKICBXZSBjYW4gaWdub3JlIHRoaXMgYWx0b2dldGhlciBiZWNhdXNlIGNvbnZlcnRpbmcgZiB0byB0eXBlIEkgaXMKICBndWFyYW50ZWVkIHRvIHRydW5jYXRlIHRoZSBmcmFjdGlvbmFsIHBhcnQgb2ZmLCBhbmQgdGhlcmVmb3JlCiAgSShmKSB3aWxsIGFsd2F5cyBiZSBpbiB0aGUgcmFuZ2UKICBbc3RkOjpudW1lcmljX2xpbWl0czxJPjo6bWluKCksIHN0ZDo6bnVtZXJpY19saW1pdHM8ST46Om1heCgpXS4KKi8KCiAgcmV0dXJuIEkoZik7Cn0KCnRlbXBsYXRlPGNsYXNzIEksIGNsYXNzIEY+IHZvaWQgdGVzdChjb25zdCBjaGFyKiBtc2csIEYgZikKewogIEkgaSA9IHRydW5jQW5kQ2FwPEksRj4oZik7CiAgY291dCA8PAogICAgbXNnIDw8CiAgICBzZXRpb3NmbGFncyhpb3NfYmFzZTo6c2hvd3BvcykgPDwKICAgIHNldHcoMTQpIDw8IHNldHByZWNpc2lvbigxMikgPDwKICAgIGYgPDwgIiAtPiAiIDw8CiAgICBpIDw8CiAgICByZXNldGlvc2ZsYWdzKGlvc19iYXNlOjpzaG93cG9zKSA8PAogICAgZW5kbDsKfQoKI2RlZmluZSBURVNUKEksRixWQUwpIFwKICB0ZXN0PEksRj4oI0YgIiAtPiAiICNJICI6ICIsIFZBTCk7CgppbnQgbWFpbigpCnsKICBURVNUKHNob3J0LCBmbG9hdCwgICAgIC0xLjc1Zik7CiAgVEVTVChzaG9ydCwgZmxvYXQsICAgICAtMS4yNWYpOwogIFRFU1Qoc2hvcnQsIGZsb2F0LCAgICAgKzAuMDBmKTsKICBURVNUKHNob3J0LCBmbG9hdCwgICAgICsxLjI1Zik7CiAgVEVTVChzaG9ydCwgZmxvYXQsICAgICArMS43NWYpOwoKICBURVNUKHNob3J0LCBmbG9hdCwgLTMyNzY5LjAwZik7CiAgVEVTVChzaG9ydCwgZmxvYXQsIC0zMjc2OC41MGYpOwogIFRFU1Qoc2hvcnQsIGZsb2F0LCAtMzI3NjguMDBmKTsKICBURVNUKHNob3J0LCBmbG9hdCwgLTMyNzY3Ljc1Zik7CiAgVEVTVChzaG9ydCwgZmxvYXQsIC0zMjc2Ny4yNWYpOwogIFRFU1Qoc2hvcnQsIGZsb2F0LCAtMzI3NjcuMDBmKTsKICBURVNUKHNob3J0LCBmbG9hdCwgLTMyNzY2LjAwZik7CiAgVEVTVChzaG9ydCwgZmxvYXQsICszMjc2Ni4wMGYpOwogIFRFU1Qoc2hvcnQsIGZsb2F0LCArMzI3NjcuMDBmKTsKICBURVNUKHNob3J0LCBmbG9hdCwgKzMyNzY3LjI1Zik7CiAgVEVTVChzaG9ydCwgZmxvYXQsICszMjc2Ny43NWYpOwogIFRFU1Qoc2hvcnQsIGZsb2F0LCArMzI3NjguMDBmKTsKICBURVNUKHNob3J0LCBmbG9hdCwgKzMyNzY4LjUwZik7CiAgVEVTVChzaG9ydCwgZmxvYXQsICszMjc2OS4wMGYpOwoKICBURVNUKGludCwgZmxvYXQsIC0yMTQ3NDgzOTA0LjAwZik7CiAgVEVTVChpbnQsIGZsb2F0LCAtMjE0NzQ4MzY0OC4wMGYpOwogIFRFU1QoaW50LCBmbG9hdCwgLTE2Nzc3MjE4LjAwZik7CiAgVEVTVChpbnQsIGZsb2F0LCAtMTY3NzcyMTYuMDBmKTsKICBURVNUKGludCwgZmxvYXQsIC0xNjc3NzIxNS4wMGYpOwogIFRFU1QoaW50LCBmbG9hdCwgKzE2Nzc3MjE1LjAwZik7CiAgVEVTVChpbnQsIGZsb2F0LCArMTY3NzcyMTYuMDBmKTsKICBURVNUKGludCwgZmxvYXQsICsxNjc3NzIxOC4wMGYpOwogIFRFU1QoaW50LCBmbG9hdCwgKzIxNDc0ODM2NDguMDBmKTsKICBURVNUKGludCwgZmxvYXQsICsyMTQ3NDgzOTA0LjAwZik7CgogIFRFU1QoaW50LCBkb3VibGUsIC0yMTQ3NDgzNjQ5LjAwKTsKICBURVNUKGludCwgZG91YmxlLCAtMjE0NzQ4MzY0OC4wMCk7CiAgVEVTVChpbnQsIGRvdWJsZSwgLTIxNDc0ODM2NDcuNzUpOwogIFRFU1QoaW50LCBkb3VibGUsIC0yMTQ3NDgzNjQ3LjI1KTsKICBURVNUKGludCwgZG91YmxlLCAtMjE0NzQ4MzY0Ny4wMCk7CiAgVEVTVChpbnQsIGRvdWJsZSwgKzIxNDc0ODM2NDcuMDApOwogIFRFU1QoaW50LCBkb3VibGUsICsyMTQ3NDgzNjQ3LjI1KTsKICBURVNUKGludCwgZG91YmxlLCArMjE0NzQ4MzY0Ny43NSk7CiAgVEVTVChpbnQsIGRvdWJsZSwgKzIxNDc0ODM2NDguMDApOwogIFRFU1QoaW50LCBkb3VibGUsICsyMTQ3NDgzNjQ5LjAwKTsKCiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCAgICAgICAgICAtMS4wMCk7CiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCAgICAgICAgICArMS4wMCk7CiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCArNDI5NDk2NzI5NS4wMCk7CiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCArNDI5NDk2NzI5NS4yNSk7CiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCArNDI5NDk2NzI5NS43NSk7CiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCArNDI5NDk2NzI5Ni4wMCk7CiAgVEVTVCh1bnNpZ25lZCwgZG91YmxlLCArNDI5NDk2NzI5Ny4wMCk7CgogIHJldHVybiAwOwp9Cg==