1.. _tutorial_commonops: 2 3Common operators 4================ 5 6After having explained how mp++'s :ref:`type coercion <tutorial_numtower>` works, we can now move on to 7describe how mp++'s classes can be used to perform mathematical computations. 8 9All of mp++'s multiprecision classes support the four basic arithmetic operations (:math:`+`, :math:`-`, 10:math:`\times` and :math:`\div`) via overloaded binary operators: 11 12.. code-block:: c++ 13 14 auto r1 = int_t{4} + int_t{3}; 15 assert(r1 == 7); 16 17 auto r2 = rat_t{4, 3} - rat_t{2, 5}; 18 assert(r2 == rat_t{14, 15}); 19 20 auto r3 = real128{5} * real128{2}; 21 assert(r3 == 10.); 22 23 auto r4 = real{5} / real{2}; 24 assert(r4 == 2.5); 25 26It is of course possible to mix operands of different types, and the type of the result will be determined 27by the :ref:`type coercion rules <tutorial_numtower>` explained earlier: 28 29.. code-block:: c++ 30 31 auto r1 = int_t{4} + 3; // r1 will be of type int_t. 32 assert(r1 == 7); 33 34 auto r2 = -0.75 + rat_t{1, 2}; // r2 will be of type double. 35 assert(r2 == -.25); 36 37 auto r3 = real128{5} * 2; // r3 will be of type real128. 38 assert(r3 == 10.); 39 40 auto r4 = real{5} / int_t{2}; // r4 will be of type real. 41 assert(r4 == 2.5); 42 43The behaviour of the division operator varies depending on the types involved. If only 44integral types are involved, division truncates, and division by zero throws 45a :cpp:class:`~mppp::zero_division_error` exception: 46 47.. code-block:: c++ 48 49 auto r1 = int_t{5} / 2; // Integral division truncates. 50 assert(r1 == 2); 51 52 int_t{1} / 0; // This will throw a zero_division_error exception. 53 54If floating-point types are involved, division by zero is allowed and results in infinity: 55 56.. code-block:: c++ 57 58 auto r1 = real128{1} / 0; // Floating-point division by zero generates an infinity. 59 assert(isinf(r1)) 60 61Rational division is always exact, unless the divisor is zero: 62 63.. code-block:: c++ 64 65 auto r1 = rat_t{3} / 4; 66 assert(r1 == rat_t{3, 4}); 67 68 rat_t{2} / 0; // This will throw a zero_division_error exception. 69 70The in-place versions of the binary operators are available as well. Given a binary operator, its 71corresponding in-place counterpart behaves as a binary operation followed by assignment: 72 73.. code-block:: c++ 74 75 int_t r1{4}; 76 r1 += 5; // Equivalent to: r1 = r1 + 5 77 assert(r1 == 9); 78 79 rat_t r2{4, 3}; 80 r2 -= 1.5; // Equivalent to: r2 = r2 - 1.5 81 assert(r2 == rat_t{-1, 6}); 82 83 real128 r3{5}; 84 r3 *= rat_t{1, 2}; // Equivalent to: r3 = r3 * rat_t{1, 2} 85 assert(r3 == 2.5); 86 87 real r4{42}; 88 r4 /= real128{0}; // Equivalent to: r4 = r4 / real128{0} 89 assert(isinf(r4)); 90 91It is also possible to use fundamental C++ types on the left-hand side of in-place operators: 92 93.. code-block:: c++ 94 95 int n = 5; 96 n += int_t{5}; 97 assert(n == 10); 98 99 n -= rat_t{3, 4} 100 assert(n == 9); 101 102 double x = 1.5; 103 x *= real128{2}; 104 assert(x == 3.); 105 106 x /= real{3}; 107 assert(x == 1.); 108 109The identity, negation, pre/post increment/decrement operators are also supported for all of 110mp++'s multiprecision classes: 111 112.. code-block:: c++ 113 114 int_t n; 115 assert(++n == 1); 116 n++; 117 assert(n == 2); 118 assert(--n == 1); 119 n--; 120 assert(n == 0); 121 122 rat_t q{1, 2}; 123 assert(+q == q); 124 assert(-q == rat_t{-1, 2}); 125 126All of mp++'s multiprecision classes are contextually convertible to ``bool``, following the usual rule 127that nonzero values convert to ``true`` and zero values convert to ``false``: 128 129.. code-block:: c++ 130 131 int_t n{3}; 132 if (n) { 133 std::cout << "n is nonzero!\n"; 134 } 135 136 rat_t q{0}; 137 if (!q) { 138 std::cout << "q is zero!\n"; 139 } 140 141 real r{1.23}; 142 if (!!r) { 143 std::cout << "r is nonzero!\n"; 144 } 145 146In addition to the common arithmetic operators, all of mp++'s multiprecision classes support the relational 147operators :math:`=` and :math:`\neq`. Real-valued types also support the comparison operators 148:math:`>`, :math:`\geq`, :math:`<` and :math:`\leq`. Any combination 149of multiprecision and numerical C++ types is supported: 150 151.. code-block:: c++ 152 153 assert(int_t{42} == 42); 154 assert(3 != rat_t{1, 3}); 155 assert(0.9 < int_t{1}); 156 assert(real128{15} <= int_t{15}); 157 assert(real{"inf", 100} > rat_t{123, 456}); 158 assert(int_t{4} >= rat_t{16, 4}); 159 160The comparison operators treat NaN values in the standard way: comparing NaN to any other value returns always 161``false``, apart from the :math:`\neq` operator which always returns ``true`` when NaN is involved. For the floating-point multiprecision 162classes, custom comparison functions with special NaN handling are also available (e.g., :cpp:func:`~mppp::real_lt()`, 163:cpp:func:`~mppp::real128_equal_to()`, etc.). These functions can be used as replacements for the comparison operators 164in facilities of the standard library such as ``std::sort()``, ``std::set``, etc. 165