132 lines
6.6 KiB
Plaintext
132 lines
6.6 KiB
Plaintext
[/
|
|
Copyright 2011 - 2020 John Maddock.
|
|
Copyright 2013 - 2019 Paul A. Bristow.
|
|
Copyright 2013 Christopher Kormanyos.
|
|
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt).
|
|
]
|
|
|
|
[section:conversions Constructing and Interconverting Between Number Types]
|
|
|
|
All of the number types that are based on `number` have certain conversion rules in common.
|
|
In particular:
|
|
|
|
* Any number type can be constructed (or assigned) from any __fundamental arithmetic type, as long
|
|
as the conversion isn't lossy (for example float to int conversion):
|
|
|
|
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.
|
|
|
|
* A number can be explicitly constructed from an arithmetic type, even when the conversion is lossy:
|
|
|
|
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.
|
|
|
|
* A `number` can be converted to any __fundamental type, via the `convert_to` member function:
|
|
|
|
mpz_int z(2);
|
|
int i = z.convert_to<int>(); // sets i to 2
|
|
|
|
* Conversions to rational numbers from floating-point ones are always allowed, and are exact and implicit
|
|
as long as the rational number uses an unbounded integer type. Please be aware that constructing a rational
|
|
number from an extended precision floating-point type with a large exponent range can effectively run the system
|
|
out of memory, as in the extreme case ['2[super max_exponent] / CHAR_BITS] bytes of storage may be required. This
|
|
does not represent a problem for __fundamental floating-point types however, as the exponent range for these is rather
|
|
limited.
|
|
|
|
* Conversions to floating-point numbers from rational ones are rounded to nearest (less than 0.5 __ULP error)
|
|
as long as the floating-point number is binary, and the integer type used by the rational number is unbounded.
|
|
|
|
Additional conversions may be supported by particular backends.
|
|
|
|
* A `number` can be converted to any __fundamental type, via an explicit conversion operator:
|
|
this functionality is only available on compilers supporting C++11's explicit conversion syntax.
|
|
|
|
mpz_int z(2);
|
|
int i = z; // Error, implicit conversion not allowed.
|
|
int j = static_cast<int>(z); // OK explicit conversion.
|
|
|
|
* Any number type can be ['explicitly] constructed (or assigned) from a `const char*` or a `std::string`:
|
|
|
|
// 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
|
|
|
|
* Any number type will interoperate with the __fundamental types in arithmetic expressions as long as the conversions
|
|
are not lossy:
|
|
|
|
// 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.
|
|
|
|
* Any number type can be streamed to and from the C++ iostreams:
|
|
|
|
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;
|
|
|
|
* Interconversions between number types of the same family are allowed and are implicit conversions if no
|
|
loss of precision is involved, and explicit if it is:
|
|
|
|
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.
|
|
|
|
* Some interconversions between number types are completely generic, and are always available, albeit the conversions are always ['explicit]:
|
|
|
|
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
|
|
|
|
* Other interconversions may be allowed as special cases, whenever the backend allows it:
|
|
|
|
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.
|
|
|
|
[endsect] [/section:conversions Constructing and Interconverting Between Number Types]
|