Unexpected floor division with ndarrays on python 3

オープン
#275 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
25/100
issue の種類
バグ
明瞭さ
説明が足りない
活発さ
停滞
技術スタック
cpp, python
領域
backend

調査の方向性

提供された main.cpp を添付の CMakeLists.txt とともに、記載された Python 2.7 および 3.6 の構成でビルドし、出力された除算結果を比較します。関連する examples/ コードを読み、再現した出力を使って Python 3 の動作が想定どおりか、また切り捨てない除算のサポートされた経路が存在するかを判断します。完了の条件は、maintainer が確認した説明、または正確に特定された fix です。

索引モデルが issue の本文から書いたものです。

説明

Our primarily C++ code base uses an embedded python to do computation with help from boost::python. We are in the process of porting to python 3. We have noticed that it appears that the / operator when acting on a pair of boost::python::numpy::ndarray's yields floor division. That is to say the results are numerically consistent with constructing the same arrays in a python interpreter and then performing arr1 // arr2. We do did not see this behaviour when linking against python27.dll. To make my issue concrete I prepared an example based on those provided in the examples/ folder. It was built on windows 10 using:

  • MSVC 2015
  • Python 2.7.16
  • Python 3.6.8
  • cmake 3.16
  • Ninja 1.9.0
  • Boost 1.70.0

main.cpp was:

#include <boost/python/numpy.hpp>
#include <iostream>

namespace p = boost::python;
namespace np = boost::python::numpy;

typedef float arr_dtype;

int main(int argc, char **argv)
{
  Py_Initialize();
  np::initialize();

  arr_dtype raw_array1[] = {1.53f, 2.53f, 3.53f, 4.53f};
  np::ndarray nd_array1 = np::from_data(raw_array1, np::dtype::get_builtin<arr_dtype>(),
                                        p::make_tuple(4),
                                        p::make_tuple(4),
                                        p::object());

  arr_dtype raw_array2[] = {0.1f};
  np::ndarray nd_array2 = np::from_data(raw_array2, np::dtype::get_builtin<arr_dtype>(),
                                        p::make_tuple(1),
                                        p::make_tuple(1),
                                        p::object());

  std::cout << "ndarray 1 is " << p::extract<char const *>(p::str(nd_array1)) << std::endl;
  std::cout << "ndarray 2 is " << p::extract<char const *>(p::str(nd_array2)) << std::endl;

  //

  p::object result_array_div = nd_array1 / nd_array2;

  std::cout << "operator/ division of arrays is " << p::extract<char const *>(p::str(result_array_div)) << std::endl;

  return 0;
}

For Python 27 the output when running main.exe was consistent with our expectations:

ndarray 1 is [1.53 2.53 3.53 4.53]
ndarray 2 is [0.1]
operator/ division of arrays is [15.299999 25.3      35.3      45.300003]

For Python 36 the result when running main.exe was not consistent with our (possibly misguided) expectations:

ndarray 1 is [1.53 2.53 3.53 4.53]
ndarray 2 is [0.1]
operator/ division of arrays is [15. 25. 35. 45.]

Is this expected behaviour? Is there any way to enforce non-floor division when using the / operator and python 3?

For reference the CMakeLists.txt was:

cmake_minimum_required(VERSION 3.16)

project(test_boost_numpy_division)

# version selection

if (BUILD_PY3)
   set(python_package_name "Python3")
   set(BOOST_ROOT "${BOOST_ROOT_PY3}")
   set(py_dll_path "${Python3_ROOT_DIR}/python36.dll")
   set(py_maj_min_version "36")
else()
   set(python_package_name "Python2")
   set(BOOST_ROOT "${BOOST_ROOT_PY2}")
   set(py_dll_path "C:/Windows/System32/python27.dll")
   set(py_maj_min_version "27")
endif()

set(boost_python_module_name "python${py_maj_min_version}")
set(boost_numpy_module_name "numpy${py_maj_min_version}")

# python config

find_package (${python_package_name} COMPONENTS Development REQUIRED)

# boost config

set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_LIBS OFF)

find_package(Boost REQUIRED COMPONENTS ${boost_python_module_name} ${boost_numpy_module_name} unit_test_framework)

#

add_executable(main)
target_sources(main PRIVATE main.cpp)

target_link_libraries(main ${python_package_name}::Python)
target_link_libraries(main Boost::${boost_python_module_name} Boost::${boost_numpy_module_name})

set_target_properties( main
   PROPERTIES
   ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

# 

file(COPY "${Boost_LIBRARY_DIRS}/" DESTINATION "${CMAKE_BINARY_DIR}/bin")
file(COPY "${py_dll_path}" DESTINATION "${CMAKE_BINARY_DIR}/bin")
主要言語
C++
スター
537
フォーク
223
平均マージ
11時間 22分
マージ済み PR(30日)
2

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

boostorg/python のほかの issue

boostorg/python の issue をすべて見る

似ている issue

C++ の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。