如何捕获 boost::wrapexcept 从 cpp_int?

huangapple go评论69阅读模式
英文:

How to catch boost::wrapexcept from cpp_int?

问题

For some reason there was a change of behavior between boost 1.78 and 1.79 causing now cpp_int convert_to<double> conversion throwing exceptions for very big numbers. Sometimes it is overflow_error, sometimes domain_error.

I have not found if it is intentional change or not, but right now as a quick first step I would like just to react on this and preserve the old behavior of our code, which was giving infinity for such numbers, std::numeric_limits<double>::max.

But I have trouble catching the exception. How can I catch instance of boost::wrapexcept<std::overflow_error>? Is some special handling required? Following simple code - see behavior comparison boost 78 vs 79 here - is not catching the exception but just terminates with
terminate called after throwing an instance of 'boost::wrapexceptstd::overflow_error'
what(): Error in function float_next(double): Overflow Error

#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>

int main() {
    std::string strNumber = "179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625";
    boost::multiprecision::cpp_int number(strNumber);

    try {
        std::cout << number.convert_to<double>() << "\n";
    } catch (boost::wrapexcept<std::overflow_error> &e) {
        std::cout << "boost exception caught" << "\n";
    } catch (...) {
        std::cout << "some exception caught" << "\n";
    }
    
    std::cout << "finished" << "\n";
}

I am expecting at least "some exception caught" line to be called, but it is not. Thanks for help.

Note after reading some answers:
The code is just an example. My current concern is not to convert the number to double. That is another following issue. More important for me right now is actually to catch the exception somehow so that I can return std::numeric_limits<double>::max() instead of exception, and the existing program will work the same way as with older boost (breaking change concerns).

Note 2: This seems to be a bug in boost, caused by throwing an exception in noexcept method. That terminates the program without the possibility to catch the exception. Thanks @Ext3h for help. I reported the thing in boost and will properly answer and close this issue if confirmed.

英文:

For some reason there was a change of behavior between boost 1.78 and 1.79 causing now cpp_int convert_to&lt;double&gt; conversion throwing exceptions for very big numbers. Sometimes it is overflow_error, sometimes domain_error.

I have not found if it is intentional change or not, but right now as a quick first step I would like just to react on this and preserve the old behavior of our code, which was giving infinity for such numbers, std::numeric_limits&lt;double&gt;::max.

But I have trouble catching the exception. How can I catch instance of boost::wrapexcept&lt;std::overflow_error&gt;? Is some special handling required? Following simple code - see behavior comparison boost 78 vs 79 here - is not catching the exception but just terminates with
terminate called after throwing an instance of 'boost::wrapexcept<std::overflow_error>'
what(): Error in function float_next<double>(double): Overflow Error

#include &lt;boost/multiprecision/cpp_int.hpp&gt;
#include &lt;iostream&gt;

int main() {
    std::string strNumber = &quot;179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625&quot;;
    boost::multiprecision::cpp_int number(strNumber);

    try {
        std::cout &lt;&lt; number.convert_to&lt;double&gt;() &lt;&lt; &quot;\n&quot;;
    } catch (boost::wrapexcept&lt;std::overflow_error&gt; &amp;e) {
        std::cout &lt;&lt; &quot;boost exception caught&quot; &lt;&lt; &quot;\n&quot;;
    } catch (...) {
        std::cout &lt;&lt; &quot;some exception caught&quot; &lt;&lt; &quot;\n&quot;;
    }
    
    std::cout &lt;&lt; &quot;finished&quot; &lt;&lt; &quot;\n&quot;;
}

I am expecting at least "some exception caught" line to be called, but it is not. Thanks for help.

Note after reading some answers:
The code is just an example. My current concern is not to convert the number to double. That is another following issue. More important for me right now is actually to catch the exception somehow so that I can return std::numeric_limits&lt;double&gt;::max() instead of exception and the existing program will work the same way as with older boost (breaking change concerns).

Note 2: This seems to be a bug in boost, caused by throwing an exception in noexcept method. That terminates the program without possibility to catch the exception. Thanks @Ext3h for help. I reported the thing in boost and will properly answer and close this issue if confirmed.

答案1

得分: 1

不要尝试捕获包装器 - 它继承自 std::overflow_error,这是你应该捕获的异常。

还要确保以 const std::overflow_error& 的方式捕获异常 - 如果你尝试捕获异常为其他类型,可能会导致一系列意外的副作用。具体来说,编译器将不得不为你的异常处理程序复制异常,这可能会因各种原因而失败或导致效率低下的行为。

最后,你仍然遇到的问题可能是这一行 boost::multiprecision::cpp_int number(strNumber); 已经在抛出异常。

检查异常规范:https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html

英文:

Don't try to catch the wrapper - it's inheriting from std::overflow_error and that's what you should go and catch.

Also make sure you are catching the exception as const std::overflow_error&amp; - your are running into a whole series of unexpected side effects if you ever try to catch an exception as anything other than a const reference. Namely, the compiler will have to copy the exception just for your exception handler, which may fail or lead to inefficient behavior for various reasons.

Finally, the issue you are still having is that the line boost::multiprecision::cpp_int number(strNumber); is potentially already throwing an exception.

Check the exception specification: https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html

答案2

得分: 0

To avoid try catch don't use convert_to like you did and instead of do this Boost Multiprecision float, Constructing and Interconverting Between Number Types:

不要使用convert_to来避免try catch,而是像这样做 Boost Multiprecision float, 构造和在数字类型之间进行相互转换:

#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace mp = boost::multiprecision;

int main() {
    std::string strNumber = "179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625";
    mp::cpp_int number(strNumber);

    std::cout << "Boost Multiprecision: "
                << std::setprecision(std::numeric_limits<mp::cpp_dec_float_50>::digits10)
                << number << std::endl;

    std::cout << "Double: "
                << std::setprecision(std::numeric_limits<double>::digits10)
                << number << std::endl;
}

Output:

输出:

Boost Multiprecision: 179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625
Double: 179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625

Like that you don't need try catch.

这样你就不需要try catch。

Or you can How to convert from boost::multiprecision::cpp_int to cpp_dec_float<0>:

或者你可以 如何从boost::multiprecision::cpp_int转换为cpp_dec_float<0>:

#include <boost/multiprecision/number.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>

namespace mp = boost::multiprecision;

int main() {
    using Int = mp::cpp_int;
    std::string strNumber = "179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625";
    Int number(strNumber);

    using Dec = mp::number<mp::cpp_dec_float<0>>;
    std::cout << number.convert_to<Dec>();
}

Output:

输出:

1.79769e+308

Or if you need try catch do the next thing:

或者如果你需要try catch,可以做如下操作:

#include <boost/multiprecision/number.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>

int main() {
    std::string strNumber = "179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625";
    boost::multiprecision::cpp_int number(strNumber);

    try {
        std::cout << number.convert_to<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<0>>() << "\n";
    } catch (boost::wrapexcept<std::overflow_error> const& e) {
        std::cout << "boost exception caught" << "\n";
    } catch (...) {
        std::cout << "some exception caught" << "\n";
    }

    std::cout << "finished" << "\n";
}

Output:

输出:

1.79769e+308
finished

英文:

To avoid try catch don't use convert_to like you did and instead of do this Boost Multiprecision float, Constructing and Interconverting Between Number Types:

#include &lt;boost/multiprecision/cpp_int.hpp&gt;
#include &lt;iostream&gt;
#include &lt;boost/multiprecision/cpp_dec_float.hpp&gt;

namespace mp = boost::multiprecision;

int main() {
    std::string strNumber = &quot;179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625&quot;;
    mp::cpp_int number(strNumber);

    std::cout &lt;&lt; &quot;Boost Multiprecision: &quot;
                &lt;&lt; std::setprecision(std::numeric_limits&lt;mp::cpp_dec_float_50&gt;::digits10)
                &lt;&lt; number &lt;&lt; std::endl;

    std::cout &lt;&lt; &quot;Double: &quot;
                &lt;&lt; std::setprecision(std::numeric_limits&lt;double&gt;::digits10)
                &lt;&lt; number &lt;&lt; std::endl;
}

Output:

Boost Multiprecision: 179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625
Double: 179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625

Like that you don't need try catch.

Or you can How to convert from boost::multiprecision::cpp_int to cpp_dec_float<0>:

#include &lt;boost/multiprecision/number.hpp&gt;
#include &lt;boost/multiprecision/cpp_int.hpp&gt;
#include &lt;boost/multiprecision/cpp_dec_float.hpp&gt;
#include &lt;iostream&gt;

namespace mp = boost::multiprecision;

int main() {
    using Int = mp::cpp_int;
    std::string strNumber = &quot;179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625&quot;;
    Int number(strNumber);

    using Dec = mp::number&lt;mp::cpp_dec_float&lt;0&gt;&gt;;
    std::cout &lt;&lt; number.convert_to&lt;Dec&gt;();
}

Output:

1.79769e+308

Or if you need try catch do the next thing:

#include &lt;boost/multiprecision/number.hpp&gt;
#include &lt;boost/multiprecision/cpp_int.hpp&gt;
#include &lt;boost/multiprecision/cpp_dec_float.hpp&gt;
#include &lt;iostream&gt;

int main() {
    std::string strNumber = &quot;179769313486231590617005494896502488139538923424507473845653439431848569886227202866765261632299351819569917639009010788373365912036255753178371299382143631760131695224907130882552454362167933328609537509415576609030163673758148226168953269623548572115351901405836315903312675793605327103910016259918212890625&quot;;
    boost::multiprecision::cpp_int number(strNumber);

    try {
        std::cout &lt;&lt; number.convert_to&lt;boost::multiprecision::number&lt;boost::multiprecision::cpp_dec_float&lt;0&gt;&gt;&gt;() &lt;&lt; &quot;\n&quot;;
    } catch (boost::wrapexcept&lt;std::overflow_error&gt; const&amp; e) {
        std::cout &lt;&lt; &quot;boost exception caught&quot; &lt;&lt; &quot;\n&quot;;
    } catch (...) {
        std::cout &lt;&lt; &quot;some exception caught&quot; &lt;&lt; &quot;\n&quot;;
    }

    std::cout &lt;&lt; &quot;finished&quot; &lt;&lt; &quot;\n&quot;;
}

Output:

1.79769e+308
finished

huangapple
  • 本文由 发表于 2023年5月11日 18:38:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76226715.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定