diff --git a/doc/html/boost_multiprecision/indexes/s01.html b/doc/html/boost_multiprecision/indexes/s01.html index 6b1856e3..b8bcad1a 100644 --- a/doc/html/boost_multiprecision/indexes/s01.html +++ b/doc/html/boost_multiprecision/indexes/s01.html @@ -13,9 +13,9 @@
PrevUpHomeNext
-
+

-Function Index

+Function Index

A B C D E F I L M P R S T Z

@@ -265,6 +265,14 @@
  • +

    eval_multiply_add

    +
    +
  • +
  • +

    eval_multiply_subtract

    +
    +
  • +
  • eval_pow

  • diff --git a/doc/html/boost_multiprecision/indexes/s02.html b/doc/html/boost_multiprecision/indexes/s02.html index 2706639a..29be2280 100644 --- a/doc/html/boost_multiprecision/indexes/s02.html +++ b/doc/html/boost_multiprecision/indexes/s02.html @@ -13,10 +13,10 @@
    PrevUpHomeNext
    -
    +

    -Class Index

    -

    C G I M N T

    +Class Index
    +

    C E G I M N T

    C @@ -33,6 +33,13 @@
    +E +
    +
    +
    G

    C I L M T U

    diff --git a/doc/html/boost_multiprecision/indexes/s04.html b/doc/html/boost_multiprecision/indexes/s04.html index 862dddae..3030cc3f 100644 --- a/doc/html/boost_multiprecision/indexes/s04.html +++ b/doc/html/boost_multiprecision/indexes/s04.html @@ -12,9 +12,9 @@
    PrevUpHome
    -
    +

    -Index

    +Index

    A B C D E F G I L M N O P R S T U Z

    @@ -347,6 +347,14 @@
  • +

    eval_multiply_add

    + +
  • +
  • +

    eval_multiply_subtract

    + +
  • +
  • eval_pow

  • @@ -400,6 +408,10 @@

    eval_trunc

    +
  • +

    expression_template_default

    + +
  • F @@ -676,6 +688,7 @@
  • component_type

  • default_precision

  • divide_qr

  • +
  • expression_template_default

  • fpclassify

  • integer_modulus

  • iround

  • @@ -746,6 +759,8 @@
  • eval_lt

  • eval_modulus

  • eval_multiply

  • +
  • eval_multiply_add

  • +
  • eval_multiply_subtract

  • eval_pow

  • eval_powm

  • eval_qr

  • diff --git a/doc/html/boost_multiprecision/map/hist.html b/doc/html/boost_multiprecision/map/hist.html index f7102bd0..ca0c5cca 100644 --- a/doc/html/boost_multiprecision/map/hist.html +++ b/doc/html/boost_multiprecision/map/hist.html @@ -44,6 +44,17 @@ Changed ExpressionTemplates parameter to class number to use enumerated values rather than true/false. +
  • + Changed ExpressionTemplate parameter default value to use a traits class + so that the default value depends on the backend used. +
  • +
  • + Added support for fused-multiply-add/subtract with GMP support. +
  • +
  • + Tweaked expression template unpacking to use fewer temporaries when the + LHS also appears in the RHS. +
  • diff --git a/doc/html/boost_multiprecision/map/todo.html b/doc/html/boost_multiprecision/map/todo.html index 5ab45fdb..2abdc184 100644 --- a/doc/html/boost_multiprecision/map/todo.html +++ b/doc/html/boost_multiprecision/map/todo.html @@ -17,106 +17,6 @@ -

    - Things requested in review: -

    -
      -
    • - A 2's complement fixed precision int that uses exactly N bits and no - more. -
    • -
    • - A backend for an overflow aware integers. -
    • -
    • - Each back-end should document the requirements it satisfies (not currently - scheduled for inclusion: it's deliberately an implementation detail, - and "optional" requirements are optimisations which can't be - detected by the user). -
    • -
    • - IIUC convert_to is used to emulate in c++98 compilers C++11 explicit - conversions. Could the explicit conversion operator be added on compilers - supporting it? (Done 2012/09/15). -
    • -
    • - The front-end should make the differences between implicit and explicit - construction (Done 2012/09/15). -
    • -
    • - The use of bool in template parameters could be improved by the use of - an enum class which will be more explicit. E.g enum - class expression_template - {disabled, enabled}; enum class sign - {unsigned, signed}; (Partly done 2012/09/15). -
    • -
    • - The ExpresionTemplate parameter could be defaulted to a traits class - for more sensible defaults. -
    • -
    • - The library interface should use the noexcept (BOOST_NOEXCEPT, ...) facilities - (Done 2012/09/15). -
    • -
    • - It is unfortunate that the generic mp_number front end can not make use - contexpr as not all the backends can ensure this (done - we can go quite - a way). -
    • -
    • - literals: The library doesn't provide some kind of literals. I think - that the mp_number class should provide a way to create literals if the - backend is able to. (Done 2012/09/15). -
    • -
    • - The performances of mp_number<a_trivial_adaptor<float>, false>respect - to float and mp_number<a_trivial_adaptor<int>, false> and - int should be given to show the cost of using the generic interface (Mostly - done, just need to update docs to the latest results). -
    • -
    • - The documentation should contain Throws specification on the mp_number - and backend requirements operations. (Done 2012/09/15). -
    • -
    • - The tutorial should add more examples concerning implicit or explicit - conversions. (Done 2012/09/15). -
    • -
    • - The documentation must explain how move semantics helps in this domain - and what the backend needs to do to profit from this optimization. (Done - 2012/09/15). -
    • -
    • - The rounding applied when converting must be documented. -
    • -
    • - cpp_dec_float should round to nearest. -
    • -
    • - In a = exp1 op exp2 where a occurs inside one of exp1 or exp2 then we - can optimise and eliminate one more temporary. -
    • -
    • - We can reuse temporaries in multiple subtrees (temporary caching). -
    • -
    • - Emphasise in the docs that ET's may reorder operations. -
    • -
    • - Document why we don't use proto (compile times). -
    • -
    • - Document what happens to small fixed precision cpp_int's. -
    • -
    • - Should we provide min/max overloads for expression templates? -
    • -
    • - Document why we don't abstract out addition/multiplication algorithms - etc. -
    • -

    More a list of what could be done, rather than what should be done (which may be a much smaller list!). @@ -140,6 +40,114 @@

  • Add an all C++ binary floating point type.
  • +
  • + Can ring types (exact floating point types) be supported? The answer + should be yes, but someone needs to write it, the hard part is IO and + binary-decimal convertion. +
  • +
  • + Should there be a choice of rounding mode (probably MPFR specific)? +
  • + +

    + Things requested in review: +

    +
      +
    • + A 2's complement fixed precision int that uses exactly N bits and no + more. +
    • +
    • + A backend for an overflow aware integers. +
    • +
    • + Each back-end should document the requirements it satisfies (not currently + scheduled for inclusion: it's deliberately an implementation detail, + and "optional" requirements are optimisations which can't be + detected by the user). +
    • +
    • + The use of bool in template parameters could be improved by the use of + an enum class which will be more explicit. E.g enum + class expression_template + {disabled, enabled}; enum class sign + {unsigned, signed}; (Partly done 2012/09/15). +
    • +
    • + The performances of mp_number<a_trivial_adaptor<float>, false>respect + to float and mp_number<a_trivial_adaptor<int>, false> and + int should be given to show the cost of using the generic interface (Mostly + done, just need to update docs to the latest results). +
    • +
    • + The rounding applied when converting must be documented. +
    • +
    • + cpp_dec_float should round to nearest. +
    • +
    • + We can reuse temporaries in multiple subtrees (temporary caching). +
    • +
    • + Emphasise in the docs that ET's may reorder operations. +
    • +
    • + Document why we don't use proto (compile times). +
    • +
    • + Document what happens to small fixed precision cpp_int's. +
    • +
    • + Should we provide min/max overloads for expression templates? +
    • +
    • + Document why we don't abstract out addition/multiplication algorithms + etc. +
    • +
    • + IIUC convert_to is used to emulate in c++98 compilers C++11 explicit + conversions. Could the explicit conversion operator be added on compilers + supporting it? (Done 2012/09/15). +
    • +
    • + The front-end should make the differences between implicit and explicit + construction (Done 2012/09/15). +
    • +
    • + The tutorial should add more examples concerning implicit or explicit + conversions. (Done 2012/09/15). +
    • +
    • + The documentation must explain how move semantics helps in this domain + and what the backend needs to do to profit from this optimization. (Done + 2012/09/15). +
    • +
    • + The documentation should contain Throws specification on the mp_number + and backend requirements operations. (Done 2012/09/15). +
    • +
    • + The library interface should use the noexcept (BOOST_NOEXCEPT, ...) facilities + (Done 2012/09/15). +
    • +
    • + It is unfortunate that the generic mp_number front end can not make use + contexpr as not all the backends can ensure this (done - we can go quite + a way). +
    • +
    • + literals: The library doesn't provide some kind of literals. I think + that the mp_number class should provide a way to create literals if the + backend is able to. (Done 2012/09/15). +
    • +
    • + The ExpresionTemplate parameter could be defaulted to a traits class + for more sensible defaults (done 2012/09/20). +
    • +
    • + In a = exp1 op exp2 where a occurs inside one of exp1 or exp2 then we + can optimise and eliminate one more temporary (done 2012/09/20). +
    @@ -147,9 +155,18 @@ Comments
    diff --git a/doc/html/boost_multiprecision/ref/backendconc.html b/doc/html/boost_multiprecision/ref/backendconc.html index 3550a227..2f6d4b91 100644 --- a/doc/html/boost_multiprecision/ref/backendconc.html +++ b/doc/html/boost_multiprecision/ref/backendconc.html @@ -1810,6 +1810,235 @@ + +

    + eval_multiply_add(b, cb, cb2) +

    + + +

    + void +

    + + +

    + Multiplies cb by + cb2 and adds the + result to b. When + not provided does the equivalent of creating a temporary B t + and eval_multiply(t, cb, cb2) followed by eval_add(b, t). +

    + + +

    +   +

    + + + + +

    + eval_multiply_add(b, cb, a) +

    + + +

    + void +

    + + +

    + Multiplies a by + cb and adds the + result to b. The + type of a shall + be listed in one of the type lists B::signed_types, + B::unsigned_types or B::float_types. When not provided + does the equivalent of creating a temporary B + t and eval_multiply(t, cb, a) followed by eval_add(b, t). +

    + + +

    +   +

    + + + + +

    + eval_multiply_add(b, a, cb) +

    + + +

    + void +

    + + +

    + Multiplies a by + cb and adds the + result to b. The + type of a shall + be listed in one of the type lists B::signed_types, + B::unsigned_types or B::float_types. When not provided + does the equivalent of eval_multiply_add(b, cb, a). +

    + + +

    +   +

    + + + + +

    + eval_multiply_subtract(b, cb, cb2) +

    + + +

    + void +

    + + +

    + Multiplies cb by + cb2 and subtracts + the result from b. + When not provided does the equivalent of creating a temporary + B t + and eval_multiply(t, cb, cb2) followed by eval_subtract(b, t). +

    + + +

    +   +

    + + + + +

    + eval_multiply_subtract(b, cb, a) +

    + + +

    + void +

    + + +

    + Multiplies a by + cb and subtracts + the result from b. + The type of a shall + be listed in one of the type lists B::signed_types, + B::unsigned_types or B::float_types. When not provided + does the equivalent of creating a temporary B + t and eval_multiply(t, cb, a) followed by eval_subtract(b, t). +

    + + +

    +   +

    + + + + +

    + eval_multiply_subtract(b, a, cb) +

    + + +

    + void +

    + + +

    + Multiplies a by + cb and subtracts + the result from b. + The type of a shall + be listed in one of the type lists B::signed_types, + B::unsigned_types or B::float_types. When not provided + does the equivalent of eval_multiply_subtract(b, cb, a). +

    + + +

    +   +

    + + + + +

    + eval_multiply_add(b, cb, cb2, cb3) +

    + + +

    + void +

    + + +

    + Multiplies cb by + cb2 and adds the + result to cb3 storing + the result in b. + When not provided does the equivalent of eval_multiply(b, cb, cb2) followed by eval_add(b, cb3). For brevity, only a version showing + all arguments of type B + is shown here, but you can replace up to any 2 of cb, cb2 + and cb3 with any + type type listed in one of the type lists B::signed_types, + B::unsigned_types or B::float_types. +

    + + +

    +   +

    + + + + +

    + eval_multiply_subtract(b, cb, cb2, cb3) +

    + + +

    + void +

    + + +

    + Multiplies cb by + cb2 and subtracts + from the result cb3 + storing the result in b. + When not provided does the equivalent of eval_multiply(b, cb, cb2) followed by eval_subtract(b, cb3). For brevity, only a version showing + all arguments of type B + is shown here, but you can replace up to any 2 of cb, cb2 + and cb3 with any + type type listed in one of the type lists B::signed_types, + B::unsigned_types or B::float_types. +

    + + +

    +   +

    + + +

    eval_divide(b, diff --git a/doc/html/boost_multiprecision/ref/cpp_int_ref.html b/doc/html/boost_multiprecision/ref/cpp_int_ref.html index 0b84e4e9..f1dbd5df 100644 --- a/doc/html/boost_multiprecision/ref/cpp_int_ref.html +++ b/doc/html/boost_multiprecision/ref/cpp_int_ref.html @@ -21,22 +21,28 @@ template <unsigned MinBits = 0, bool Signed = true, class Allocator = std::allocator<limb_type> > struct cpp_int_backend; +// +// Expression templates default to et_off if there is no allocator: +// +template <unsigned MinDigits, bool Signed> +struct expression_template_default<cpp_int_backend<MinDigits, Signed, void> > +{ static const expression_template_option value = et_off; }; typedef number<cpp_int_backend<> > cpp_int; // arbitrary precision integer typedef rational_adapter<cpp_int_backend<> > cpp_rational_backend; typedef number<cpp_rational_backend> cpp_rational; // arbitrary precision rational number // Fixed precision unsigned types: -typedef number<cpp_int_backend<128, false, void>, et_off> uint128_t; -typedef number<cpp_int_backend<256, false, void>, et_off> uint256_t; -typedef number<cpp_int_backend<512, false, void>, et_off> uint512_t; -typedef number<cpp_int_backend<1024, false, void>, et_off> uint1024_t; +typedef number<cpp_int_backend<128, false, void> > uint128_t; +typedef number<cpp_int_backend<256, false, void> > uint256_t; +typedef number<cpp_int_backend<512, false, void> > uint512_t; +typedef number<cpp_int_backend<1024, false, void> > uint1024_t; // Fixed precision signed types: -typedef number<cpp_int_backend<128, true, void>, et_off> int128_t; -typedef number<cpp_int_backend<256, true, void>, et_off> int256_t; -typedef number<cpp_int_backend<512, true, void>, et_off> int512_t; -typedef number<cpp_int_backend<1024, true, void>, et_off> int1024_t; +typedef number<cpp_int_backend<128, true, void> > int128_t; +typedef number<cpp_int_backend<256, true, void> > int256_t; +typedef number<cpp_int_backend<512, true, void> > int512_t; +typedef number<cpp_int_backend<1024, true, void> > int1024_t; }} // namespaces diff --git a/doc/html/boost_multiprecision/ref/number.html b/doc/html/boost_multiprecision/ref/number.html index 3c7994fc..de7a6cdc 100644 --- a/doc/html/boost_multiprecision/ref/number.html +++ b/doc/html/boost_multiprecision/ref/number.html @@ -23,7 +23,12 @@

    namespace boost{ namespace multiprecision{
     
    -template <class Backend, expression_template_option ExpressionTemplates = true>
    +enum expression_template_option { et_on = 1, et_off = 0 };
    +
    +template <class Backend> struct expression_template_default
    +{ static const expression_template_option value = et_on; };
    +
    +template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
     class number
     {
        number();
    @@ -206,7 +211,20 @@
     
             Description
           
    -
    template <class Backend, expression_template_option ExpressionTemplates = true>
    +
    enum expression_template_option { et_on = 1, et_off = 0 };
    +
    +

    + This enumerated type is used to specify whether expression templates are + turned on (et_on) or turned off (et_off). +

    +
    template <class Backend> struct expression_template_default
    +{ static const expression_template_option value = et_on; };
    +
    +

    + This traits class specifies the default expression template option to be + used with a particular Backend type. It defaults to et_on. +

    +
    template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
     class number;
     

    @@ -222,8 +240,12 @@

    ExpressionTemplates

    - A Boolean value: when true, then expression templates are enabled, - otherwise they are disabled. + A Boolean value: when et_on, + then expression templates are enabled, otherwise when set to et_off they are disabled. The default + for this parameter is computed via the traits class expression_template_default + whose member value + defaults to et_on unless + the the traits class is specialized for a particular backend.

    diff --git a/doc/html/boost_multiprecision/tut/ints/cpp_int.html b/doc/html/boost_multiprecision/tut/ints/cpp_int.html index fdfa36ff..a220dc59 100644 --- a/doc/html/boost_multiprecision/tut/ints/cpp_int.html +++ b/doc/html/boost_multiprecision/tut/ints/cpp_int.html @@ -26,22 +26,28 @@ template <unsigned MinDigits = 0, bool Signed = true, class Allocator = std::allocator<limb_type> > class cpp_int_backend; +// +// Expression templates default to et_off if there is no allocator: +// +template <unsigned MinDigits, bool Signed> +struct expression_template_default<cpp_int_backend<MinDigits, Signed, void> > +{ static const expression_template_option value = et_off; }; -typedef number<cpp_int_backend<> > cpp_int; // arbitrary precision integer +typedef number<cpp_int_backend<> > cpp_int; // arbitrary precision integer typedef rational_adapter<cpp_int_backend<> > cpp_rational_backend; -typedef number<cpp_rational_backend> cpp_rational; // arbitrary precision rational number +typedef number<cpp_rational_backend> cpp_rational; // arbitrary precision rational number // Fixed precision unsigned types: -typedef number<cpp_int_backend<128, false, void>, et_off> uint128_t; -typedef number<cpp_int_backend<256, false, void>, et_off> uint256_t; -typedef number<cpp_int_backend<512, false, void>, et_off> uint512_t; -typedef number<cpp_int_backend<1024, false, void>, et_off> uint1024_t; +typedef number<cpp_int_backend<128, false, void> > uint128_t; +typedef number<cpp_int_backend<256, false, void> > uint256_t; +typedef number<cpp_int_backend<512, false, void> > uint512_t; +typedef number<cpp_int_backend<1024, false, void> > uint1024_t; // Fixed precision signed types: -typedef number<cpp_int_backend<128, true, void>, et_off> int128_t; -typedef number<cpp_int_backend<256, true, void>, et_off> int256_t; -typedef number<cpp_int_backend<512, true, void>, et_off> int512_t; -typedef number<cpp_int_backend<1024, true, void>, et_off> int1024_t; +typedef number<cpp_int_backend<128, true, void> > int128_t; +typedef number<cpp_int_backend<256, true, void> > int256_t; +typedef number<cpp_int_backend<512, true, void> > int512_t; +typedef number<cpp_int_backend<1024, true, void> > int1024_t; }} // namespaces
    diff --git a/doc/html/index.html b/doc/html/index.html index 6352948f..0482b470 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -120,7 +120,7 @@ - +

    Last revised: September 16, 2012 at 12:00:51 GMT

    Last revised: September 20, 2012 at 15:58:33 GMT


    diff --git a/doc/multiprecision.qbk b/doc/multiprecision.qbk index b9772383..c9380777 100644 --- a/doc/multiprecision.qbk +++ b/doc/multiprecision.qbk @@ -340,22 +340,28 @@ The following back-ends provide integer arithmetic: template > class cpp_int_backend; + // + // Expression templates default to et_off if there is no allocator: + // + template + struct expression_template_default > + { static const expression_template_option value = et_off; }; - typedef number > cpp_int; // arbitrary precision integer + typedef number > cpp_int; // arbitrary precision integer typedef rational_adapter > cpp_rational_backend; - typedef number cpp_rational; // arbitrary precision rational number + typedef number cpp_rational; // arbitrary precision rational number // Fixed precision unsigned types: - typedef number, et_off> uint128_t; - typedef number, et_off> uint256_t; - typedef number, et_off> uint512_t; - typedef number, et_off> uint1024_t; + typedef number > uint128_t; + typedef number > uint256_t; + typedef number > uint512_t; + typedef number > uint1024_t; // Fixed precision signed types: - typedef number, et_off> int128_t; - typedef number, et_off> int256_t; - typedef number, et_off> int512_t; - typedef number, et_off> int1024_t; + typedef number > int128_t; + typedef number > int256_t; + typedef number > int512_t; + typedef number > int1024_t; }} // namespaces @@ -1109,7 +1115,12 @@ The following example searches for a prime `p` for which `(p-1)/2` is also proba namespace boost{ namespace multiprecision{ - template + enum expression_template_option { et_on = 1, et_off = 0 }; + + template struct expression_template_default + { static const expression_template_option value = et_on; }; + + template ::value> class number { number(); @@ -1290,14 +1301,26 @@ The following example searches for a prime `p` for which `(p-1)/2` is also proba [h4 Description] - template + enum expression_template_option { et_on = 1, et_off = 0 }; + +This enumerated type is used to specify whether expression templates are turned on (et_on) or turned off (et_off). + + template struct expression_template_default + { static const expression_template_option value = et_on; }; + +This traits class specifies the default expression template option to be used with a particular Backend type. +It defaults to `et_on`. + + template ::value> class number; Class `number` has two template arguments: [variablelist [[Backend][The actual arithmetic back-end that does all the work.]] -[[ExpressionTemplates][A Boolean value: when true, then expression templates are enabled, otherwise they are disabled.]] +[[ExpressionTemplates][A Boolean value: when `et_on`, then expression templates are enabled, otherwise when set to `et_off` they are disabled. + The default for this parameter is computed via the traits class `expression_template_default` whose member `value` defaults to `et_on` unless + the the traits class is specialized for a particular backend.]] ] number(); @@ -1698,22 +1721,28 @@ whose precision can vary at compile time (such as `mpf_float`). template > struct cpp_int_backend; + // + // Expression templates default to et_off if there is no allocator: + // + template + struct expression_template_default > + { static const expression_template_option value = et_off; }; typedef number > cpp_int; // arbitrary precision integer typedef rational_adapter > cpp_rational_backend; typedef number cpp_rational; // arbitrary precision rational number // Fixed precision unsigned types: - typedef number, et_off> uint128_t; - typedef number, et_off> uint256_t; - typedef number, et_off> uint512_t; - typedef number, et_off> uint1024_t; + typedef number > uint128_t; + typedef number > uint256_t; + typedef number > uint512_t; + typedef number > uint1024_t; // Fixed precision signed types: - typedef number, et_off> int128_t; - typedef number, et_off> int256_t; - typedef number, et_off> int512_t; - typedef number, et_off> int1024_t; + typedef number > int128_t; + typedef number > int256_t; + typedef number > int512_t; + typedef number > int1024_t; }} // namespaces @@ -2080,6 +2109,42 @@ of type B2. [[`eval_multiply(b, a, cb)`][`void`][Multiplies `a` by `cb` and stores the result in `b`. The type of `a` shall be listed in one of the type lists `B::signed_types`, `B::unsigned_types` or `B::float_types`. When not provided, does the equivalent of `eval_multiply(b, cb, a)`.][[space]]] +[[`eval_multiply_add(b, cb, cb2)`][`void`][Multiplies `cb` by `cb2` and adds the result to `b`. + When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, cb2)` followed by + `eval_add(b, t)`.][[space]]] +[[`eval_multiply_add(b, cb, a)`][`void`][Multiplies `a` by `cb` and adds the result to `b`. + The type of `a` shall be listed in one of the type lists + `B::signed_types`, `B::unsigned_types` or `B::float_types`. + When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, a)` followed by + `eval_add(b, t)`.][[space]]] +[[`eval_multiply_add(b, a, cb)`][`void`][Multiplies `a` by `cb` and adds the result to `b`. + The type of `a` shall be listed in one of the type lists + `B::signed_types`, `B::unsigned_types` or `B::float_types`. + When not provided does the equivalent of `eval_multiply_add(b, cb, a)`.][[space]]] +[[`eval_multiply_subtract(b, cb, cb2)`][`void`][Multiplies `cb` by `cb2` and subtracts the result from `b`. + When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, cb2)` followed by + `eval_subtract(b, t)`.][[space]]] +[[`eval_multiply_subtract(b, cb, a)`][`void`][Multiplies `a` by `cb` and subtracts the result from `b`. + The type of `a` shall be listed in one of the type lists + `B::signed_types`, `B::unsigned_types` or `B::float_types`. + When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, a)` followed by + `eval_subtract(b, t)`.][[space]]] +[[`eval_multiply_subtract(b, a, cb)`][`void`][Multiplies `a` by `cb` and subtracts the result from `b`. + The type of `a` shall be listed in one of the type lists + `B::signed_types`, `B::unsigned_types` or `B::float_types`. + When not provided does the equivalent of `eval_multiply_subtract(b, cb, a)`.][[space]]] +[[`eval_multiply_add(b, cb, cb2, cb3)`][`void`][Multiplies `cb` by `cb2` and adds the result to `cb3` storing the result in `b`. + When not provided does the equivalent of `eval_multiply(b, cb, cb2)` followed by + `eval_add(b, cb3)`. + For brevity, only a version showing all arguments of type `B` is shown here, but you can replace up to any 2 of + `cb`, `cb2` and `cb3` with any type type listed in one of the type lists + `B::signed_types`, `B::unsigned_types` or `B::float_types`.][[space]]] +[[`eval_multiply_subtract(b, cb, cb2, cb3)`][`void`][Multiplies `cb` by `cb2` and subtracts from the result `cb3` storing the result in `b`. + When not provided does the equivalent of `eval_multiply(b, cb, cb2)` followed by + `eval_subtract(b, cb3)`. + For brevity, only a version showing all arguments of type `B` is shown here, but you can replace up to any 2 of + `cb`, `cb2` and `cb3` with any type type listed in one of the type lists + `B::signed_types`, `B::unsigned_types` or `B::float_types`.][[space]]] [[`eval_divide(b, a)`][`void`][Divides `b` by `a`. The type of `a` shall be listed in one of the type lists `B::signed_types`, `B::unsigned_types` or `B::float_types`. When not provided, the default version calls `eval_divide(b, B(a))`] @@ -2665,6 +2730,9 @@ Windows Vista machine. * Removed "mp_" prefix from types. * Allowed mixed precision arithmetic. * Changed ExpressionTemplates parameter to class `number` to use enumerated values rather than true/false. +* Changed ExpressionTemplate parameter default value to use a traits class so that the default value depends on the backend used. +* Added support for fused-multiply-add/subtract with GMP support. +* Tweaked expression template unpacking to use fewer temporaries when the LHS also appears in the RHS. [h4 Pre-review history] @@ -2706,13 +2774,11 @@ by the user). * The use of bool in template parameters could be improved by the use of an enum class which will be more explicit. E.g `enum class expression_template {disabled, enabled}; enum class sign {unsigned, signed};` (Partly done 2012/09/15). -* The ExpresionTemplate parameter could be defaulted to a traits class for more sensible defaults. * The performances of mp_number, false>respect to float and mp_number, false> and int should be given to show the cost of using the generic interface (Mostly done, just need to update docs to the latest results). * The rounding applied when converting must be documented. * cpp_dec_float should round to nearest. -* In a = exp1 op exp2 where a occurs inside one of exp1 or exp2 then we can optimise and eliminate one more temporary. * We can reuse temporaries in multiple subtrees (temporary caching). * Emphasise in the docs that ET's may reorder operations. * Document why we don't use proto (compile times). @@ -2737,6 +2803,8 @@ contexpr as not all the backends can ensure this (done - we can go quite a way). * literals: The library doesn't provide some kind of literals. I think that the mp_number class should provide a way to create literals if the backend is able to. (Done 2012/09/15). +* The ExpresionTemplate parameter could be defaulted to a traits class for more sensible defaults (done 2012/09/20). +* In a = exp1 op exp2 where a occurs inside one of exp1 or exp2 then we can optimise and eliminate one more temporary (done 2012/09/20). @@ -2744,7 +2812,6 @@ is able to. (Done 2012/09/15). * Make fixed precision orthogonal to Allocator type in cpp_int. Possible solution - add an additional MaxBits template argument that defaults to 0 (meaning keep going till no more space/memory). -* Add support for fused multiply add (and subtract). GMP mpz_t could use this. * Can ring types (exact floating point types) be supported? The answer should be yes, but someone needs to write it (Moved to TODO list). * Should there be a choice of rounding mode (probably MPFR specific)? Moved to TODO list. * Make the exponent type for cpp_dec_float a templare parameter, maybe include support for big-integer exponents. @@ -2756,6 +2823,7 @@ Open question - what should be the default - int32_t or int64_t? (done 2012/09/ * Can we be clearer in the docs that mixed arithmetic doesn't work (no longer applicable as of 2012/09/06)? * Document round functions behaviour better (they behave as in C++11) (added note 2012/09/06). * Document limits on size of cpp_dec_float (done 2012/09/06). +* Add support for fused multiply add (and subtract). GMP mpz_t could use this (done 2012/09/20). [endsect] diff --git a/include/boost/multiprecision/cpp_int.hpp b/include/boost/multiprecision/cpp_int.hpp index 6e11c0b0..0436f657 100644 --- a/include/boost/multiprecision/cpp_int.hpp +++ b/include/boost/multiprecision/cpp_int.hpp @@ -3059,6 +3059,12 @@ BOOST_FORCEINLINE typename enable_if, Integer>::type eval_int } // namespace backends; +template +struct expression_template_default > +{ + static const expression_template_option value = et_off; +}; + using boost::multiprecision::backends::cpp_int_backend; template @@ -3069,16 +3075,16 @@ typedef rational_adapter > cpp_rational_backend; typedef number cpp_rational; // Fixed precision unsigned types: -typedef number, et_off> uint128_t; -typedef number, et_off> uint256_t; -typedef number, et_off> uint512_t; -typedef number, et_off> uint1024_t; +typedef number > uint128_t; +typedef number > uint256_t; +typedef number > uint512_t; +typedef number > uint1024_t; // Fixed precision signed types: -typedef number, et_off> int128_t; -typedef number, et_off> int256_t; -typedef number, et_off> int512_t; -typedef number, et_off> int1024_t; +typedef number > int128_t; +typedef number > int256_t; +typedef number > int512_t; +typedef number > int1024_t; #ifdef BOOST_MSVC #pragma warning(pop) diff --git a/include/boost/multiprecision/detail/default_ops.hpp b/include/boost/multiprecision/detail/default_ops.hpp index dfe1abca..d83b336d 100644 --- a/include/boost/multiprecision/detail/default_ops.hpp +++ b/include/boost/multiprecision/detail/default_ops.hpp @@ -35,10 +35,16 @@ namespace boost{ namespace multiprecision{ namespace default_ops{ // // Default versions of mixed arithmetic, these just construct a temporary // from the arithmetic value and then do the arithmetic on that, two versions -// of each depending on whether the backend can be directly constructed from type V: +// of each depending on whether the backend can be directly constructed from type V. +// +// Note that we have to provide *all* the template parameters to class number when used in +// enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter. +// Since the result of the test doesn't depend on whether expression templates are on or off +// we just use et_on everywhere. We could use a BOOST_WORKAROUND but that just obfuscates the +// code even more.... // template -inline typename enable_if_c >::value && !is_convertible::value >::type +inline typename enable_if_c >::value && !is_convertible::value >::type eval_add(T& result, V const& v) { T t; @@ -46,14 +52,14 @@ inline typename enable_if_c >::value && !is_converti eval_add(result, t); } template -inline typename enable_if_c >::value && is_convertible::value >::type +inline typename enable_if_c >::value && is_convertible::value >::type eval_add(T& result, V const& v) { T t(v); eval_add(result, t); } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_subtract(T& result, V const& v) { T t; @@ -61,14 +67,14 @@ inline typename enable_if_c >::value && !is_converti eval_subtract(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_subtract(T& result, V const& v) { T t(v); eval_subtract(result, t); } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_multiply(T& result, V const& v) { T t; @@ -76,14 +82,42 @@ inline typename enable_if_c >::value && !is_converti eval_multiply(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_multiply(T& result, V const& v) { T t(v); eval_multiply(result, t); } + +template +void eval_multiply(T& t, const U& u, const V& v); + +template +inline typename disable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v) +{ + T z; + eval_multiply(z, u, v); + eval_add(t, z); +} +template +inline typename enable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v) +{ + eval_multiply_add(t, v, u); +} +template +inline typename disable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v) +{ + T z; + eval_multiply(z, u, v); + eval_subtract(t, z); +} +template +inline typename enable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v) +{ + eval_multiply_subtract(t, v, u); +} template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide(T& result, V const& v) { T t; @@ -91,14 +125,14 @@ inline typename enable_if_c >::value && !is_converti eval_divide(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_divide(T& result, V const& v) { T t(v); eval_divide(result, t); } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus(T& result, V const& v) { T t; @@ -106,14 +140,14 @@ inline typename enable_if_c >::value && !is_converti eval_modulus(result, t); } template -inline typename enable_if_c >::value&& is_convertible::value>::type +inline typename enable_if_c >::value&& is_convertible::value>::type eval_modulus(T& result, V const& v) { T t(v); eval_modulus(result, t); } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_and(T& result, V const& v) { T t; @@ -121,14 +155,14 @@ inline typename enable_if_c >::value && !is_converti eval_bitwise_and(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_and(T& result, V const& v) { T t(v); eval_bitwise_and(result, t); } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_or(T& result, V const& v) { T t; @@ -136,14 +170,14 @@ inline typename enable_if_c >::value && !is_converti eval_bitwise_or(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_or(T& result, V const& v) { T t(v); eval_bitwise_or(result, t); } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_xor(T& result, V const& v) { T t; @@ -151,7 +185,7 @@ inline typename enable_if_c >::value && !is_converti eval_bitwise_xor(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_xor(T& result, V const& v) { T t(v); @@ -159,7 +193,7 @@ inline typename enable_if_c >::value && is_convertib } template -inline typename enable_if_c >::value && !is_convertible::value>::type +inline typename enable_if_c >::value && !is_convertible::value>::type eval_complement(T& result, V const& v) { T t; @@ -167,7 +201,7 @@ inline typename enable_if_c >::value && !is_converti eval_complement(result, t); } template -inline typename enable_if_c >::value && is_convertible::value>::type +inline typename enable_if_c >::value && is_convertible::value>::type eval_complement(T& result, V const& v) { T t(v); @@ -198,20 +232,20 @@ inline void eval_add_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_add(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) { T vv(v); eval_add(t, u, vv); } template -inline typename enable_if_c >::value>::type eval_add_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value>::type eval_add_default(T& t, const U& u, const T& v) { eval_add(t, v, u); } @@ -249,20 +283,20 @@ inline void eval_subtract_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_subtract(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) { T vv(v); eval_subtract(t, u, vv); } template -inline typename enable_if_c >::value>::type eval_subtract_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value>::type eval_subtract_default(T& t, const U& u, const T& v) { eval_subtract(t, v, u); t.negate(); @@ -279,9 +313,6 @@ inline void eval_subtract(T& t, const U& u, const V& v) eval_subtract_default(t, u, v); } -template -void eval_multiply(T& t, const U& u, const V& v); - template inline void eval_multiply_default(T& t, const T& u, const T& v) { @@ -300,20 +331,20 @@ inline void eval_multiply_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_multiply(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) { T vv(v); eval_multiply(t, u, vv); } template -inline typename enable_if_c >::value>::type eval_multiply_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value>::type eval_multiply_default(T& t, const U& u, const T& v) { eval_multiply(t, v, u); } @@ -329,6 +360,47 @@ inline void eval_multiply(T& t, const U& u, const V& v) eval_multiply_default(t, u, v); } +template +inline typename disable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) +{ + if((void*)&x == (void*)&t) + { + T z; + z = x; + eval_multiply_add(t, u, v, z); + } + else + { + eval_multiply(t, u, v); + eval_add(t, x); + } +} +template +inline typename enable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) +{ + eval_multiply_add(t, v, u, x); +} +template +inline typename disable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x) +{ + if((void*)&x == (void*)&t) + { + T z; + z = x; + eval_multiply_subtract(t, u, v, z); + } + else + { + eval_multiply(t, u, v); + eval_subtract(t, x); + } +} +template +inline typename enable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x) +{ + eval_multiply_subtract(t, v, u, x); +} + template void eval_divide(T& t, const U& u, const V& v); @@ -350,27 +422,27 @@ inline void eval_divide_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_divide(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) { T vv(v); eval_divide(t, u, vv); } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) { T uu; uu = u; eval_divide(t, uu, v); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) { T uu(u); eval_divide(t, uu, v); @@ -408,27 +480,27 @@ inline void eval_modulus_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_modulus(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) { T vv(v); eval_modulus(t, u, vv); } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) { T uu; uu = u; eval_modulus(t, uu, v); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) { T uu(u); eval_modulus(t, uu, v); @@ -466,20 +538,20 @@ inline void eval_bitwise_and_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_bitwise_and(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) { T vv(v); eval_bitwise_and(t, u, vv); } template -inline typename enable_if_c >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v) { eval_bitwise_and(t, v, u); } @@ -516,20 +588,20 @@ inline void eval_bitwise_or_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_bitwise_or(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) { T vv(v); eval_bitwise_or(t, u, vv); } template -inline typename enable_if_c >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v) { eval_bitwise_or(t, v, u); } @@ -566,20 +638,20 @@ inline void eval_bitwise_xor_default(T& t, const T& u, const T& v) } } template -inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) { T vv; vv = v; eval_bitwise_xor(t, u, vv); } template -inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) +inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) { T vv(v); eval_bitwise_xor(t, u, vv); } template -inline typename enable_if_c >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v) +inline typename enable_if_c >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v) { eval_bitwise_xor(t, v, u); } @@ -1272,7 +1344,7 @@ func(const number& arg)\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ - , number \ + , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg \ @@ -1328,8 +1400,8 @@ func(const number& arg, const number& a)\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ - , number \ - , number \ + , number \ + , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ @@ -1350,7 +1422,7 @@ func(const number& arg, const detail::expression \ - , number \ + , number \ , detail::expression \ >(\ detail::BOOST_JOIN(func, _funct)() \ @@ -1373,7 +1445,7 @@ func(const detail::expression& arg, const number \ , detail::expression \ - , number \ + , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ @@ -1417,7 +1489,7 @@ func(const number& arg, const Arithmetic& a)\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ - , number \ + , number \ , Arithmetic\ >(\ detail::BOOST_JOIN(func, _funct)() \ @@ -1464,7 +1536,7 @@ func(const Arithmetic& arg, const number& a)\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , Arithmetic \ - , number \ + , number \ >(\ detail::BOOST_JOIN(func, _funct)() \ , arg,\ @@ -1568,7 +1640,7 @@ func(const number& arg, Arg2 const& a)\ return detail::expression<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ - , number \ + , number \ , Arg2\ >(\ detail::BOOST_JOIN(func, _funct)() \ diff --git a/include/boost/multiprecision/detail/et_ops.hpp b/include/boost/multiprecision/detail/et_ops.hpp index 1e35c9be..81fb9580 100644 --- a/include/boost/multiprecision/detail/et_ops.hpp +++ b/include/boost/multiprecision/detail/et_ops.hpp @@ -77,6 +77,66 @@ inline typename enable_if >(a, b); } // +// Fused multiply add: +// +template +inline typename enable_if::result_type>, + detail::expression::left_type, typename detail::expression::right_type, V> >::type + operator + (const V& a, const detail::expression& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, V>(b.left(), b.right(), a); +} +template +inline typename enable_if::result_type>, + detail::expression::left_type, typename detail::expression::right_type, V> >::type + operator + (const detail::expression& a, const V& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, V>(a.left(), a.right(), b); +} +template +inline detail::expression::left_type, typename detail::expression::right_type, number > + operator + (const number& a, const detail::expression& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number >(b.left(), b.right(), a); +} +template +inline detail::expression::left_type, typename detail::expression::right_type, number > + operator + (const detail::expression& a, const number& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number >(a.left(), a.right(), b); +} +// +// Fused multiply subtract: +// +template +inline typename enable_if::result_type>, + detail::expression::left_type, typename detail::expression::right_type, V> > >::type + operator - (const V& a, const detail::expression& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, V> > + (detail::expression::left_type, typename detail::expression::right_type, V>(b.left(), b.right(), a)); +} +template +inline typename enable_if::result_type>, + detail::expression::left_type, typename detail::expression::right_type, V> >::type + operator - (const detail::expression& a, const V& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, V>(a.left(), a.right(), b); +} +template +inline detail::expression::left_type, typename detail::expression::right_type, number > > + operator - (const number& a, const detail::expression& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number > > + (detail::expression::left_type, typename detail::expression::right_type, number >(b.left(), b.right(), a)); +} +template +inline detail::expression::left_type, typename detail::expression::right_type, number > + operator - (const detail::expression& a, const number& b) +{ + return detail::expression::left_type, typename detail::expression::right_type, number >(a.left(), a.right(), b); +} +// // Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries: // template diff --git a/include/boost/multiprecision/detail/functions/constants.hpp b/include/boost/multiprecision/detail/functions/constants.hpp index 537b7bd1..b32f3f28 100644 --- a/include/boost/multiprecision/detail/functions/constants.hpp +++ b/include/boost/multiprecision/detail/functions/constants.hpp @@ -246,7 +246,7 @@ const T& get_constant_ln2() static bool b = false; if(!b) { - calc_log2(result, boost::multiprecision::detail::digits2 >::value); + calc_log2(result, boost::multiprecision::detail::digits2 >::value); b = true; } @@ -262,7 +262,7 @@ const T& get_constant_e() static bool b = false; if(!b) { - calc_e(result, boost::multiprecision::detail::digits2 >::value); + calc_e(result, boost::multiprecision::detail::digits2 >::value); b = true; } @@ -278,7 +278,7 @@ const T& get_constant_pi() static bool b = false; if(!b) { - calc_pi(result, boost::multiprecision::detail::digits2 >::value); + calc_pi(result, boost::multiprecision::detail::digits2 >::value); b = true; } diff --git a/include/boost/multiprecision/detail/functions/pow.hpp b/include/boost/multiprecision/detail/functions/pow.hpp index c0c2abc8..2ed9da1d 100644 --- a/include/boost/multiprecision/detail/functions/pow.hpp +++ b/include/boost/multiprecision/detail/functions/pow.hpp @@ -90,7 +90,7 @@ void hyp0F0(T& H0F0, const T& x) typedef typename mpl::front::type ui_type; BOOST_ASSERT(&H0F0 != &x); - long tol = boost::multiprecision::detail::digits2 >::value; + long tol = boost::multiprecision::detail::digits2 >::value; T t; T x_pow_n_div_n_fact(x); @@ -146,7 +146,7 @@ void hyp1F0(T& H1F0, const T& a, const T& x) eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact); eval_add(H1F0, si_type(1)); T lim; - eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2 >::value); + eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2 >::value); if(eval_get_sign(lim) < 0) lim.negate(); @@ -154,7 +154,7 @@ void hyp1F0(T& H1F0, const T& a, const T& x) T term, part; // Series expansion of hyperg_1f0(a; ; x). - for(n = 2; n < boost::multiprecision::detail::digits2 >::value + 10; n++) + for(n = 2; n < boost::multiprecision::detail::digits2 >::value + 10; n++) { eval_multiply(x_pow_n_div_n_fact, x); eval_divide(x_pow_n_div_n_fact, n); @@ -167,7 +167,7 @@ void hyp1F0(T& H1F0, const T& a, const T& x) if(lim.compare(term) >= 0) break; } - if(n >= boost::multiprecision::detail::digits2 >::value + 10) + if(n >= boost::multiprecision::detail::digits2 >::value + 10) BOOST_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge")); } @@ -193,7 +193,7 @@ void eval_exp(T& result, const T& x) bool isneg = eval_get_sign(x) < 0; if(type == FP_NAN) { - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; } else if(type == FP_INFINITE) @@ -218,7 +218,7 @@ void eval_exp(T& result, const T& x) xx.negate(); // Check the range of the argument. - static const canonical_exp_type maximum_arg_for_exp = std::numeric_limits >::max_exponent == 0 ? (std::numeric_limits::max)() : std::numeric_limits >::max_exponent; + static const canonical_exp_type maximum_arg_for_exp = std::numeric_limits >::max_exponent == 0 ? (std::numeric_limits::max)() : std::numeric_limits >::max_exponent; if(xx.compare(maximum_arg_for_exp) >= 0) { @@ -226,7 +226,7 @@ void eval_exp(T& result, const T& x) if(isneg) result = ui_type(0); else - result = std::numeric_limits >::has_infinity ? std::numeric_limits >::infinity().backend() : (std::numeric_limits >::max)().backend(); + result = std::numeric_limits >::has_infinity ? std::numeric_limits >::infinity().backend() : (std::numeric_limits >::max)().backend(); return; } if(xx.compare(si_type(1)) <= 0) @@ -234,7 +234,7 @@ void eval_exp(T& result, const T& x) // // Use series for exp(x) - 1: // - T lim = std::numeric_limits >::epsilon().backend(); + T lim = std::numeric_limits >::epsilon().backend(); unsigned k = 2; exp_series = xx; result = si_type(1); @@ -344,7 +344,7 @@ void eval_log(T& result, const T& arg) else eval_subtract(result, t); - eval_multiply(lim, result, std::numeric_limits >::epsilon().backend()); + eval_multiply(lim, result, std::numeric_limits >::epsilon().backend()); if(eval_get_sign(lim) < 0) lim.negate(); INSTRUMENT_BACKEND(lim); @@ -465,7 +465,7 @@ inline void eval_pow(T& result, const T& x, const T& a) if((eval_get_sign(x) < 0) && !bo_a_isint) { - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); } T t, da; @@ -564,7 +564,7 @@ namespace detail{ ui_type k = 1; T lim(x); - eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2 >::value); + eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2 >::value); do { diff --git a/include/boost/multiprecision/detail/functions/trig.hpp b/include/boost/multiprecision/detail/functions/trig.hpp index 4e57b070..e4086427 100644 --- a/include/boost/multiprecision/detail/functions/trig.hpp +++ b/include/boost/multiprecision/detail/functions/trig.hpp @@ -36,7 +36,7 @@ void hyp0F1(T& result, const T& b, const T& x) T tol; tol = ui_type(1); - eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2 >::value); + eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2 >::value); eval_multiply(tol, result); if(eval_get_sign(tol) < 0) tol.negate(); @@ -87,7 +87,7 @@ void eval_sin(T& result, const T& x) { case FP_INFINITE: case FP_NAN: - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; case FP_ZERO: result = ui_type(0); @@ -233,7 +233,7 @@ void eval_cos(T& result, const T& x) { case FP_INFINITE: case FP_NAN: - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; case FP_ZERO: result = ui_type(1); @@ -391,7 +391,7 @@ void hyp2F1(T& result, const T& a, const T& b, const T& c, const T& x) eval_add(result, ui_type(1)); T lim; - eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2 >::value); + eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2 >::value); if(eval_get_sign(lim) < 0) lim.negate(); @@ -447,7 +447,7 @@ void eval_asin(T& result, const T& x) { case FP_NAN: case FP_INFINITE: - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; case FP_ZERO: result = ui_type(0); @@ -464,7 +464,7 @@ void eval_asin(T& result, const T& x) int c = xx.compare(ui_type(1)); if(c > 0) { - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; } else if(c == 0) @@ -524,7 +524,7 @@ void eval_asin(T& result, const T& x) eval_subtract(result, s); T lim; - eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2 >::value); + eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2 >::value); if(eval_get_sign(s) < 0) s.negate(); if(eval_get_sign(lim) < 0) @@ -546,7 +546,7 @@ inline void eval_acos(T& result, const T& x) { case FP_NAN: case FP_INFINITE: - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; case FP_ZERO: result = get_constant_pi(); @@ -559,7 +559,7 @@ inline void eval_acos(T& result, const T& x) if(c > 0) { - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; } else if(c == 0) @@ -591,7 +591,7 @@ void eval_atan(T& result, const T& x) switch(eval_fpclassify(x)) { case FP_NAN: - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); return; case FP_ZERO: result = ui_type(0); @@ -656,7 +656,7 @@ void eval_atan(T& result, const T& x) static const boost::int32_t double_digits10_minus_a_few = std::numeric_limits::digits10 - 3; T s, c, t; - for(boost::int32_t digits = double_digits10_minus_a_few; digits <= std::numeric_limits >::digits10; digits *= 2) + for(boost::int32_t digits = double_digits10_minus_a_few; digits <= std::numeric_limits >::digits10; digits *= 2) { eval_sin(s, result); eval_cos(c, result); @@ -710,7 +710,7 @@ void eval_atan2(T& result, const T& y, const T& x) { if(eval_fpclassify(x) == FP_INFINITE) { - result = std::numeric_limits >::quiet_NaN().backend(); + result = std::numeric_limits >::quiet_NaN().backend(); } else { diff --git a/include/boost/multiprecision/detail/number_base.hpp b/include/boost/multiprecision/detail/number_base.hpp index 0f6ed2bd..b6f9c65f 100644 --- a/include/boost/multiprecision/detail/number_base.hpp +++ b/include/boost/multiprecision/detail/number_base.hpp @@ -20,7 +20,13 @@ enum expression_template_option et_on = 1 }; -template +template +struct expression_template_default +{ + static const expression_template_option value = et_on; +}; + +template ::value> class number; template @@ -180,6 +186,8 @@ struct bitwise_or_immediates{}; struct bitwise_xor_immediates{}; struct complement_immediates{}; struct function{}; +struct multiply_add{}; +struct multiply_subtract{}; template struct backend_type; @@ -207,7 +215,14 @@ template struct is_mp_number_exp > : public mpl::true_{}; template -struct combine_expression; +struct combine_expression +{ +#ifdef BOOST_NO_DECLTYPE + typedef typename mpl::if_c sizeof(T2) ? T1, T2>::type type; +#else + typedef decltype(T1() + T2()) type; +#endif +}; template struct combine_expression, T2> diff --git a/include/boost/multiprecision/detail/number_compare.hpp b/include/boost/multiprecision/detail/number_compare.hpp index dda75e64..00832838 100644 --- a/include/boost/multiprecision/detail/number_compare.hpp +++ b/include/boost/multiprecision/detail/number_compare.hpp @@ -152,14 +152,14 @@ inline typename enable_if_c& a, const Arithmetic& b) { using default_ops::eval_eq; - return !eval_eq(a.backend(), number::canonical_value(b)); + return !eval_eq(a.backend(), number::canonical_value(b)); } template inline typename enable_if_c, Arithmetic>::value, bool>::type operator != (const Arithmetic& a, const number& b) { using default_ops::eval_eq; - return !eval_eq(b.backend(), number::canonical_value(a)); + return !eval_eq(b.backend(), number::canonical_value(a)); } template inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type diff --git a/include/boost/multiprecision/gmp.hpp b/include/boost/multiprecision/gmp.hpp index 6495445b..5780cbe9 100644 --- a/include/boost/multiprecision/gmp.hpp +++ b/include/boost/multiprecision/gmp.hpp @@ -1288,6 +1288,14 @@ inline void eval_add(gmp_int& t, const gmp_int& o) { mpz_add(t.data(), t.data(), o.data()); } +inline void eval_multiply_add(gmp_int& t, const gmp_int& a, const gmp_int& b) +{ + mpz_addmul(t.data(), a.data(), b.data()); +} +inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, const gmp_int& b) +{ + mpz_submul(t.data(), a.data(), b.data()); +} inline void eval_subtract(gmp_int& t, const gmp_int& o) { mpz_sub(t.data(), t.data(), o.data()); @@ -1310,6 +1318,14 @@ inline void eval_add(gmp_int& t, unsigned long i) { mpz_add_ui(t.data(), t.data(), i); } +inline void eval_multiply_add(gmp_int& t, const gmp_int& a, unsigned long i) +{ + mpz_addmul_ui(t.data(), a.data(), i); +} +inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, unsigned long i) +{ + mpz_submul_ui(t.data(), a.data(), i); +} inline void eval_subtract(gmp_int& t, unsigned long i) { mpz_sub_ui(t.data(), t.data(), i); @@ -1335,6 +1351,20 @@ inline void eval_add(gmp_int& t, long i) else mpz_sub_ui(t.data(), t.data(), -i); } +inline void eval_multiply_add(gmp_int& t, const gmp_int& a, long i) +{ + if(i > 0) + mpz_addmul_ui(t.data(), a.data(), i); + else + mpz_submul_ui(t.data(), a.data(), -i); +} +inline void eval_multiply_subtract(gmp_int& t, const gmp_int& a, long i) +{ + if(i > 0) + mpz_submul_ui(t.data(), a.data(), i); + else + mpz_addmul_ui(t.data(), a.data(), -i); +} inline void eval_subtract(gmp_int& t, long i) { if(i > 0) @@ -1895,19 +1925,6 @@ inline bool eval_is_zero(const gmp_rational& val) { return mpq_sgn(val.data()) == 0; } -inline number numerator(const number& val) -{ - number result; - mpz_set(result.backend().data(), (mpq_numref(val.backend().data()))); - return result; -} -inline number denominator(const number& val) -{ - number result; - mpz_set(result.backend().data(), (mpq_denref(val.backend().data()))); - return result; -} - template inline bool eval_eq(gmp_rational& a, const T& b) { @@ -2109,6 +2126,21 @@ struct component_type > typedef number type; }; +template +inline number numerator(const number& val) +{ + number result; + mpz_set(result.backend().data(), (mpq_numref(val.backend().data()))); + return result; +} +template +inline number denominator(const number& val) +{ + number result; + mpz_set(result.backend().data(), (mpq_denref(val.backend().data()))); + return result; +} + #ifdef BOOST_NO_SFINAE_EXPR namespace detail{ diff --git a/include/boost/multiprecision/number.hpp b/include/boost/multiprecision/number.hpp index 2ec587b7..aae260c7 100644 --- a/include/boost/multiprecision/number.hpp +++ b/include/boost/multiprecision/number.hpp @@ -160,9 +160,9 @@ public: m_backend = canonical_value(v); return *this; } - template + template typename disable_if, number& >::type - assign(const number& v) + assign(const number& v) { // // Attempt a generic interconvertion: @@ -209,6 +209,17 @@ public: return *this; } + template + number& operator+=(const detail::expression& e) + { + // + // Fused multiply-add: + // + using default_ops::eval_multiply_add; + eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref())); + return *this; + } + template typename enable_if, number& >::type operator+=(const V& v) @@ -249,6 +260,17 @@ public: return *this; } + template + number& operator-=(const detail::expression& e) + { + // + // Fused multiply-subtract: + // + using default_ops::eval_multiply_subtract; + eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref())); + return *this; + } + number& operator *= (const self_type& e) { @@ -673,6 +695,18 @@ private: using default_ops::eval_multiply; eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); } + template + void do_assign(const Exp& e, const detail::multiply_add&) + { + using default_ops::eval_multiply_add; + eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value())); + } + template + void do_assign(const Exp& e, const detail::multiply_subtract&) + { + using default_ops::eval_multiply_subtract; + eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value())); + } template void do_assign(const Exp& e, const detail::divide_immediates&) @@ -710,13 +744,13 @@ private: // Ignore the right node, it's *this, just add the left: do_add(e.left(), typename left_type::tag_type()); } - else if(bl || br) + else if(bl && br) { self_type temp(e); temp.m_backend.swap(this->m_backend); } - else if(left_depth >= right_depth) - { + else if(bl || (left_depth >= right_depth)) + { // br is always false, but if bl is true we must take the this branch: do_assign(e.left(), typename left_type::tag_type()); do_add(e.right(), typename right_type::tag_type()); } @@ -749,13 +783,13 @@ private: do_subtract(e.left(), typename left_type::tag_type()); m_backend.negate(); } - else if(bl || br) + else if(bl && br) { self_type temp(e); temp.m_backend.swap(this->m_backend); } - else if(left_depth >= right_depth) - { + else if(bl || (left_depth >= right_depth)) + { // br is always false, but if bl is true we must take the this branch: do_assign(e.left(), typename left_type::tag_type()); do_subtract(e.right(), typename right_type::tag_type()); } @@ -788,13 +822,13 @@ private: // Ignore the right node, it's *this, just add the left: do_multiplies(e.left(), typename left_type::tag_type()); } - else if(bl || br) + else if(bl && br) { self_type temp(e); temp.m_backend.swap(this->m_backend); } - else if(left_depth >= right_depth) - { + else if(bl || (left_depth >= right_depth)) + { // br is always false, but if bl is true we must take the this branch: do_assign(e.left(), typename left_type::tag_type()); do_multiplies(e.right(), typename right_type::tag_type()); } @@ -818,7 +852,7 @@ private: // Ignore the left node, it's *this, just add the right: do_divide(e.right(), typename right_type::tag_type()); } - else if(bl || br) + else if(br) { self_type temp(e); temp.m_backend.swap(this->m_backend); @@ -848,7 +882,7 @@ private: // Ignore the left node, it's *this, just add the right: do_modulus(e.right(), typename right_type::tag_type()); } - else if(bl || br) + else if(br) { self_type temp(e); temp.m_backend.swap(this->m_backend); diff --git a/include/boost/multiprecision/rational_adapter.hpp b/include/boost/multiprecision/rational_adapter.hpp index b7a37ed8..b3f2ad16 100644 --- a/include/boost/multiprecision/rational_adapter.hpp +++ b/include/boost/multiprecision/rational_adapter.hpp @@ -213,17 +213,6 @@ inline int eval_get_sign(const rational_adapter& val) return eval_get_sign(val.data().numerator().backend()); } -template -inline number numerator(const number >& val) -{ - return val.backend().data().numerator(); -} -template -inline number denominator(const number >& val) -{ - return val.backend().data().denominator(); -} - template inline void assign_components(rational_adapter& result, const V& v1, const V& v2) { @@ -232,6 +221,9 @@ inline void assign_components(rational_adapter& result, const V& v1, } // namespace backends +template +struct expression_template_default > : public expression_template_default {}; + template struct number_category > : public mpl::int_{}; @@ -243,6 +235,17 @@ struct component_type > typedef number type; }; +template +inline number numerator(const number, ET>& val) +{ + return val.backend().data().numerator(); +} +template +inline number denominator(const number, ET>& val) +{ + return val.backend().data().denominator(); +} + #ifdef BOOST_NO_SFINAE_EXPR namespace detail{ diff --git a/test/test_arithmetic.cpp b/test/test_arithmetic.cpp index 7128c20a..e38ea081 100644 --- a/test/test_arithmetic.cpp +++ b/test/test_arithmetic.cpp @@ -1085,6 +1085,79 @@ void test_negative_mixed(boost::mpl::true_ const&) BOOST_TEST(c == 30); c = static_cast(n4) * a; BOOST_TEST(c == 50 * 20); + + n1 = -2; + n2 = -3; + n3 = -4; + a = static_cast(n1); + b = static_cast(n2); + c = static_cast(n3); + d = a + b * c; + BOOST_TEST(d == -2 + -3 * -4); + d = static_cast(n1) + b * c; + BOOST_TEST(d == -2 + -3 * -4); + d = a + static_cast(n2) * c; + BOOST_TEST(d == -2 + -3 * -4); + d = a + b * static_cast(n3); + BOOST_TEST(d == -2 + -3 * -4); + d = static_cast(n1) + static_cast(n2) * c; + BOOST_TEST(d == -2 + -3 * -4); + d = static_cast(n1) + b * static_cast(n3); + BOOST_TEST(d == -2 + -3 * -4); + a += static_cast(n2) * c; + BOOST_TEST(a == -2 + -3 * -4); + a = static_cast(n1); + a += b * static_cast(n3); + BOOST_TEST(a == -2 + -3 * -4); + a = static_cast(n1); + + d = b * c + a; + BOOST_TEST(d == -2 + -3 * -4); + d = b * c + static_cast(n1); + BOOST_TEST(d == -2 + -3 * -4); + d = static_cast(n2) * c + a; + BOOST_TEST(d == -2 + -3 * -4); + d = b * static_cast(n3) + a; + BOOST_TEST(d == -2 + -3 * -4); + d = static_cast(n2) * c + static_cast(n1); + BOOST_TEST(d == -2 + -3 * -4); + d = b * static_cast(n3) + static_cast(n1); + BOOST_TEST(d == -2 + -3 * -4); + + a = -20; + d = a - b * c; + BOOST_TEST(d == -20 - -3 * -4); + n1 = -20; + d = static_cast(n1) - b * c; + BOOST_TEST(d == -20 - -3 * -4); + d = a - static_cast(n2) * c; + BOOST_TEST(d == -20 - -3 * -4); + d = a - b * static_cast(n3); + BOOST_TEST(d == -20 - -3 * -4); + d = static_cast(n1) - static_cast(n2) * c; + BOOST_TEST(d == -20 - -3 * -4); + d = static_cast(n1) - b * static_cast(n3); + BOOST_TEST(d == -20 - -3 * -4); + a -= static_cast(n2) * c; + BOOST_TEST(a == -20 - -3 * -4); + a = static_cast(n1); + a -= b * static_cast(n3); + BOOST_TEST(a == -20 - -3 * -4); + + a = -2; + d = b * c - a; + BOOST_TEST(d == -3 * -4 - -2); + n1 = -2; + d = b * c - static_cast(n1); + BOOST_TEST(d == -3 * -4 - -2); + d = static_cast(n2) * c - a; + BOOST_TEST(d == -3 * -4 - -2); + d = b * static_cast(n3) - a; + BOOST_TEST(d == -3 * -4 - -2); + d = static_cast(n2) * c - static_cast(n1); + BOOST_TEST(d == -3 * -4 - -2); + d = b * static_cast(n3) - static_cast(n1); + BOOST_TEST(d == -3 * -4 - -2); } template @@ -1209,6 +1282,77 @@ void test_mixed(const boost::mpl::true_&) r = static_cast(4 * n4) / Real(4); BOOST_TEST(r == static_cast(n4)); test_negative_mixed(boost::mpl::bool_::is_signed>()); + + n1 = 2; + n2 = 3; + n3 = 4; + Real a(n1), b(n2), c(n3), d; + d = a + b * c; + BOOST_TEST(d == 2 + 3 * 4); + d = static_cast(n1) + b * c; + BOOST_TEST(d == 2 + 3 * 4); + d = a + static_cast(n2) * c; + BOOST_TEST(d == 2 + 3 * 4); + d = a + b * static_cast(n3); + BOOST_TEST(d == 2 + 3 * 4); + d = static_cast(n1) + static_cast(n2) * c; + BOOST_TEST(d == 2 + 3 * 4); + d = static_cast(n1) + b * static_cast(n3); + BOOST_TEST(d == 2 + 3 * 4); + a += static_cast(n2) * c; + BOOST_TEST(a == 2 + 3 * 4); + a = static_cast(n1); + a += b * static_cast(n3); + BOOST_TEST(a == 2 + 3 * 4); + a = static_cast(n1); + + d = b * c + a; + BOOST_TEST(d == 2 + 3 * 4); + d = b * c + static_cast(n1); + BOOST_TEST(d == 2 + 3 * 4); + d = static_cast(n2) * c + a; + BOOST_TEST(d == 2 + 3 * 4); + d = b * static_cast(n3) + a; + BOOST_TEST(d == 2 + 3 * 4); + d = static_cast(n2) * c + static_cast(n1); + BOOST_TEST(d == 2 + 3 * 4); + d = b * static_cast(n3) + static_cast(n1); + BOOST_TEST(d == 2 + 3 * 4); + + a = 20; + d = a - b * c; + BOOST_TEST(d == 20 - 3 * 4); + n1 = 20; + d = static_cast(n1) - b * c; + BOOST_TEST(d == 20 - 3 * 4); + d = a - static_cast(n2) * c; + BOOST_TEST(d == 20 - 3 * 4); + d = a - b * static_cast(n3); + BOOST_TEST(d == 20 - 3 * 4); + d = static_cast(n1) - static_cast(n2) * c; + BOOST_TEST(d == 20 - 3 * 4); + d = static_cast(n1) - b * static_cast(n3); + BOOST_TEST(d == 20 - 3 * 4); + a -= static_cast(n2) * c; + BOOST_TEST(a == 20 - 3 * 4); + a = static_cast(n1); + a -= b * static_cast(n3); + BOOST_TEST(a == 20 - 3 * 4); + + a = 2; + d = b * c - a; + BOOST_TEST(d == 3 * 4 - 2); + n1 = 2; + d = b * c - static_cast(n1); + BOOST_TEST(d == 3 * 4 - 2); + d = static_cast(n2) * c - a; + BOOST_TEST(d == 3 * 4 - 2); + d = b * static_cast(n3) - a; + BOOST_TEST(d == 3 * 4 - a); + d = static_cast(n2) * c - static_cast(n1); + BOOST_TEST(d == 3 * 4 - 2); + d = b * static_cast(n3) - static_cast(n1); + BOOST_TEST(d == 3 * 4 - 2); } template @@ -1612,6 +1756,19 @@ void test() BOOST_TEST(c == 20 * 30 + 22); c = 22 + (a * b); BOOST_TEST(c == 20 * 30 + 22); + c = 10; + ac = a + b * c; + BOOST_TEST(ac == 20 + 30 * 10); + ac = b * c + a; + BOOST_TEST(ac == 20 + 30 * 10); + a = a + b * c; + BOOST_TEST(a == 20 + 30 * 10); + a = 20; + b = a + b * c; + BOOST_TEST(b == 20 + 30 * 10); + b = 30; + c = a + b * c; + BOOST_TEST(c == 20 + 30 * 10); // // Test conditionals: @@ -1681,8 +1838,8 @@ int main() #endif #ifdef TEST_CPP_INT_3 // Again with "trivial" backends: - test, boost::multiprecision::et_off > >(); - test, boost::multiprecision::et_off > >(); + test > >(); + test > >(); #endif #ifdef TEST_CPP_INT_BR test >(); diff --git a/test/test_constants.cpp b/test/test_constants.cpp index 770b8721..b7f6afe9 100644 --- a/test/test_constants.cpp +++ b/test/test_constants.cpp @@ -159,8 +159,8 @@ inline bool is_mpfr(const T&) return false; } #if defined(TEST_MPFR_50) -template -inline bool is_mpfr(const boost::multiprecision::number >&) +template +inline bool is_mpfr(const boost::multiprecision::number, ET>&) { return true; } diff --git a/test/test_float_io.cpp b/test/test_float_io.cpp index 591e550d..74ba8898 100644 --- a/test/test_float_io.cpp +++ b/test/test_float_io.cpp @@ -41,8 +41,8 @@ #include #if defined(TEST_MPF_50) -template -bool is_mpf(const boost::multiprecision::number >&) +template +bool is_mpf(const boost::multiprecision::number, ET>&) { return true; } #endif template