PyBind11:boost::multiprecision::cpp_int到Python 我对使用C++优化Python计算有兴趣。这对我来说没有多大意义,我想知道是否有人知道如何将boost数据类型,特别是cpp_int,转换为Python数据类型,以便我可以返回计算结果。我尝试做的一个简单示例是阶乘: #include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <boost/multiprecision/cpp_int.hpp> using boost::multiprecision::cpp_int; namespace py = pybind11; py::int_ fact(int i) { cpp_int prod = 1; while(i-- >= 1){ prod *= (i+1); } return py::cast(prod); } PYBIND11_MODULE(fact, m) { m.def("fact", &fact,R"pbdoc( Returns the factorial of a number. )pbdoc"); }

PyBind11:boost::multiprecision::cpp_int到Python 我对使用C++优化Python计算有兴趣。这对我来说没有多大意义,我想知道是否有人知道如何将boost数据类型,特别是cpp_int,转换为Python数据类型,以便我可以返回计算结果。我尝试做的一个简单示例是阶乘: #include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <boost/multiprecision/cpp_int.hpp> using boost::multiprecision::cpp_int; namespace py = pybind11; py::int_ fact(int i) { cpp_int prod = 1; while(i-- >= 1){ prod *= (i+1); } return py::cast(prod); } PYBIND11_MODULE(fact, m) { m.def("fact", &fact,R"pbdoc( Returns the factorial of a number. )pbdoc"); },python,c++,boost,casting,pybind11,Python,C++,Boost,Casting,Pybind11,及 我还使用位于C:\ProgramFilesx86\MicrosoftVisualStudio\2017\BuildTools\VC\Redist\MSVC\14.16.27012\onecore\x64\Microsoft.VC141.CRT中的vcruntime140.dll,我将其复制并粘贴到C:\MinGW\lib中。我还将C:\Anaconda3\Lib\distutils\cygwingcompiler.py中的所有字符串gcc更改为g++,但没有更改其中包含gcc的变量名 关键词

我还使用位于C:\ProgramFilesx86\MicrosoftVisualStudio\2017\BuildTools\VC\Redist\MSVC\14.16.27012\onecore\x64\Microsoft.VC141.CRT中的vcruntime140.dll,我将其复制并粘贴到C:\MinGW\lib中。我还将C:\Anaconda3\Lib\distutils\cygwingcompiler.py中的所有字符串gcc更改为g++,但没有更改其中包含gcc的变量名

关键词: pybind11;促进C++和Python;boost::multiprecision::cpp_int

我实现了这一点:

#include <boost/multiprecision/cpp_int.hpp>
#include <iomanip>
#include <pybind11/pybind11.h>
#include <sstream>

using cpp_int = boost::multiprecision::cpp_int;
namespace py = pybind11;

namespace pybind11
{
namespace detail
{
    template <>
    struct type_caster<cpp_int> {
        /**
         * This macro establishes the name 'cpp_int' in
         * function signatures and declares a local variable
         * 'value' of type cpp_int
         */
        PYBIND11_TYPE_CASTER(cpp_int, _("cpp_int"));

        /**
         * Conversion part 1 (Python->C++): convert a PyObject into a cpp_int
         * instance or return false upon failure. The second argument
         * indicates whether implicit conversions should be applied.
         */
        bool load(handle src, bool)
        {
            // Convert into base 16 string (PyNumber_ToBase prepend '0x')
            PyObject* tmp = PyNumber_ToBase(src.ptr(), 16);
            if (!tmp) return false;

            std::string s = py::cast<std::string>(tmp);
            value = cpp_int{s}; // explicit cast from string to cpp_int,
                                // don't need a base here because
                                // `PyNumber_ToBase` already prepended '0x'
            Py_DECREF(tmp);

            /* Ensure return code was OK (to avoid out-of-range errors etc) */
            return !PyErr_Occurred();
        }

        /**
         * Conversion part 2 (C++ -> Python): convert an cpp_int instance into
         * a Python object. The second and third arguments are used to
         * indicate the return value policy and parent object (for
         * ``return_value_policy::reference_internal``) and are generally
         * ignored by implicit casters.
         */
        static handle cast(const cpp_int& src, return_value_policy, handle)
        {
            // Convert cpp_int to base 16 string
            std::ostringstream oss;
            oss << std::hex << src;
            return PyLong_FromString(oss.str().c_str(), nullptr, 16);
        }
    };
} // namespace detail
} // namespace pybind11

py::int_ fact(int i)
{
    cpp_int prod = 1;
    while (i-- > 1) prod *= i + 1;
    return py::cast(prod);
}

PYBIND11_MODULE(python_example, m)
{
    m.def("fact", &fact, R"pbdoc(
        Returns the factorial of a number.
    )pbdoc");
}

可能不是最快的方法,因为它首先将cpp_int转换为临时的base 16字符串,然后将该字符串转换为Python整数。

cpp_int对于某些后端来说可能只是C库mpz的包装器?所以,直接包C可能会更容易。@ USE14717如果我把MPZ包起来,我会如何在C++中使用C++并通过PybDun11返回它?如果你需要在C++和Python中使用它,我的建议就不行了。如果你直接从CyPython直接访问,你会创建一个Python扩展模块。也许你可以试着用CppItIn替换它。您可以将cpp_int转换为base16字符串,并通过将PyNumber转换为string base16并基于此Python字符串对象构造一个cpp_int,从而将其传递给C++->Python和Python->C++进行转换。
C:\Users\15734>python
Python 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
C:\Users\15734>g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/x86_64-w64-mingw32/8.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../src/configure --enable-languages=c,c++ --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --disable-multilib --prefix=/c/temp/gcc/dest --with-sysroot=/c/temp/gcc/dest --disable-libstdcxx-pch --disable-libstdcxx-verbose --disable-nls --disable-shared --disable-win32-registry --with-tune=haswell --enable-threads=posix --enable-libgomp
Thread model: posix
gcc version 8.2.0 (GCC)
#include <boost/multiprecision/cpp_int.hpp>
#include <iomanip>
#include <pybind11/pybind11.h>
#include <sstream>

using cpp_int = boost::multiprecision::cpp_int;
namespace py = pybind11;

namespace pybind11
{
namespace detail
{
    template <>
    struct type_caster<cpp_int> {
        /**
         * This macro establishes the name 'cpp_int' in
         * function signatures and declares a local variable
         * 'value' of type cpp_int
         */
        PYBIND11_TYPE_CASTER(cpp_int, _("cpp_int"));

        /**
         * Conversion part 1 (Python->C++): convert a PyObject into a cpp_int
         * instance or return false upon failure. The second argument
         * indicates whether implicit conversions should be applied.
         */
        bool load(handle src, bool)
        {
            // Convert into base 16 string (PyNumber_ToBase prepend '0x')
            PyObject* tmp = PyNumber_ToBase(src.ptr(), 16);
            if (!tmp) return false;

            std::string s = py::cast<std::string>(tmp);
            value = cpp_int{s}; // explicit cast from string to cpp_int,
                                // don't need a base here because
                                // `PyNumber_ToBase` already prepended '0x'
            Py_DECREF(tmp);

            /* Ensure return code was OK (to avoid out-of-range errors etc) */
            return !PyErr_Occurred();
        }

        /**
         * Conversion part 2 (C++ -> Python): convert an cpp_int instance into
         * a Python object. The second and third arguments are used to
         * indicate the return value policy and parent object (for
         * ``return_value_policy::reference_internal``) and are generally
         * ignored by implicit casters.
         */
        static handle cast(const cpp_int& src, return_value_policy, handle)
        {
            // Convert cpp_int to base 16 string
            std::ostringstream oss;
            oss << std::hex << src;
            return PyLong_FromString(oss.str().c_str(), nullptr, 16);
        }
    };
} // namespace detail
} // namespace pybind11

py::int_ fact(int i)
{
    cpp_int prod = 1;
    while (i-- > 1) prod *= i + 1;
    return py::cast(prod);
}

PYBIND11_MODULE(python_example, m)
{
    m.def("fact", &fact, R"pbdoc(
        Returns the factorial of a number.
    )pbdoc");
}