Skip to content

Single precision float treated as doubles, np.float32 incompatible? #2036

@aldanor

Description

@aldanor

(on 2.4.3)
Looks like there's a mix of a few issues in the example below:

  • First, least precision floats would be picked if you don't carefully order your overloads (as @ax3l mentioned in Float Overloads Specialize to Least Precision #1512), sounds like that's something that may be done automatically
  • There's no builtin float32, so both floats and doubles show up as 'float' on Python side; this would have been fine unless...
  • ... passing np.float32() actually worked. You may expect it would have worked but because it doesn't inherit from builtin.float it won't. Is it worth special-casing scalar float32 case?

I do sort of understand where this is coming from, but someone who doesn't know py11 internals may assume that "well, np.float32[:] arrays work, and np.float64[:] arrays work, and I can pass np.float64 and builtin.float for double-type arguments, so np.float32 should work as well?", but then it gets converted to a different type altogether.

#include <pybind11/pybind11.h>

namespace py = pybind11;

auto f_double(double x) { return "double"; }
auto f_float(float x) { return "float"; }
auto f_int(int x) { return "int"; }

PYBIND11_MODULE(py11, m) {
    // double/float: these two overloads have to be ordered this way... (see #1512)
    m.def("f", &f_double, py::arg("x"));
    m.def("f", &f_float, py::arg("x"));
    // int
    m.def("f", &f_int, py::arg("x"));
}

Let's give this a spin:

>>> f?
Overloaded function.
1. f(x: float) -> str  # <-- ?
2. f(x: float) -> str
3. f(x: int) -> str

>>> f(1)
'int'  # ok

>>> f(1.)
'double'  # note: would have been float if two overloads were swapped

>>> f(np.float64(1.))
'double'  # so far so good

>>> f(np.float32(1.))
<ipython-input-7-4d9dada8d141>:1: DeprecationWarning: an integer is required (got type numpy.float32).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
  f(np.float32(1.))
'int'  # not so good

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions