Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Constructing and Interconverting Between Number Types

All of the number types that are based on number have certain conversion rules in common. In particular:

cpp_dec_float_50 df(0.5);   // OK construction from double
cpp_int          i(450);    // OK constructs from signed int
cpp_int          j = 3.14;  // Error, lossy conversion.
cpp_int          i(3.14);       // OK explicit conversion
i = static_cast<cpp_int>(3.14)  // OK explicit conversion
i.assign(3.14);                 // OK, explicit assign and avoid a temporary from the cast above
i = 3.14;                       // Error, no implicit assignment operator for lossy conversion.
cpp_int          j = 3.14;      // Error, no implicit constructor for lossy conversion.
mpz_int z(2);
int i = z.template convert_to<int>(); // sets i to 2

Additional conversions may be supported by particular backends.

mpz_int z(2);
int i = z;                     // Error, implicit conversion not allowed.
int j = static_cast<int>(z);   // OK explicit conversion.
// pi to 50 places from a string:
cpp_dec_float_50 df("3.14159265358979323846264338327950288419716939937510");
// Integer type will automatically detect "0x" and "0" prefixes and parse the string accordingly:
cpp_int          i("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000");
// Invalid input always results in a std::runtime_error being thrown:
i = static_cast<cpp_int>("3.14");
// implicit conversions from strings are not allowed:
i = "23"; // Error, no assignment operator for implicit conversion from string
// assign member function, avoids having to create a temporary via a static_cast:
i.assign("23");  // OK
// pi to 50 places from a string:
cpp_dec_float_50 df = "3.14159265358979323846264338327950288419716939937510";
// Multiply by 2 - using an integer literal here is usually more efficient
// than constructing a temporary:
df *= 2;

// You can't mix integer types with floats though:
cpp_int i = 2;
i *= 3.14;  // Error, no *= operator will be found.
cpp_dec_float_50 df = "3.14159265358979323846264338327950288419716939937510";
// Now print at full precision:
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::max_digits10)
   << df << std::endl
cpp_int i = 1;
i <<= 256;
// Now print in hex format with prefix:
std::cout << std::hex << std::showbase << i << std::endl;
int128_t     i128 = 0;
int266_t     i256 = i128;  // OK implicit widening conversion
i128_t            = i256;  // Error, no assignment operator found, narrowing conversion is explicit
i128_t            = static_cast<int128_t>(i256); // OK, explicit narrowing conversion

mpz_int      z    = 0;
mpf_float    f    = z;    // OK, GMP handles this conversion natively, and it's not lossy and therefore implicit

mpf_float_50 f50  = 2;
f                 = f50;  // OK, conversion from fixed to variable precision, f will have 50 digits precision.
f50               = f;    // Error, conversion from variable to fixed precision is potentially lossy, explicit cast required.
cpp_int cppi(2);
// We can always convert between numbers of the same category - 
// int to int, rational to rational, or float to float, so this is OK
// as long as we use an explicit conversion:
mpz_int z(cppi);
// We can always promote from int to rational, int to float, or rational to float:
cpp_rational     cppr(cppi);  // OK, int to rational
cpp_dec_float_50 df(cppi);    // OK, int to float
df                  = static_cast<cpp_dec_float_50>(cppr);  // OK, explicit rational to float conversion
// However narrowing and/or implicit conversions always fail:
cppi                =   df;    // Compiler error, conversion not allowed
mpf_t     m;           // Native GMP type.
mpf_init_set_ui(m, 0); // set to a value;
mpf_float i(m);        // copies the value of the native type.

More information on what additional types a backend supports conversions from are given in the tutorial for each backend. The converting constructor will be implicit if the backend's converting constructor is also implicit, and explicit if the backends converting constructor is also explicit.


PrevUpHomeNext