boost/libs/multiprecision/doc/tutorial_conversions.qbk
2021-10-05 21:37:46 +02:00

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]