Skip to content

Commit 7530e2d

Browse files
Merge pull request serge-sans-paille#1105 from serge-sans-paille/fix/conversion-accuracy
Fix/conversion accuracy
2 parents b9a3238 + 51762de commit 7530e2d

File tree

19 files changed

+387
-275
lines changed

19 files changed

+387
-275
lines changed

pythran/pythonic/include/math/isinf.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ PYTHONIC_NS_BEGIN
88

99
namespace math
1010
{
11-
DEFINE_FUNCTOR_2(isinf, std::isinf);
11+
template <class T>
12+
bool isinf(T const &v)
13+
{
14+
return std::isinf(v);
15+
}
16+
DEFINE_FUNCTOR(pythonic::math, isinf);
1217
}
1318
PYTHONIC_NS_END
1419

pythran/pythonic/include/numpy/asscalar.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ PYTHONIC_NS_BEGIN
99

1010
namespace numpy
1111
{
12+
template <class T>
13+
using asscalar_result_type = typename std::conditional<
14+
std::is_integral<T>::value, long,
15+
typename std::conditional<std::is_floating_point<T>::value, double,
16+
std::complex<double>>::type>::type;
17+
1218
template <class E>
13-
typename E::dtype asscalar(E const &expr);
19+
asscalar_result_type<typename E::dtype> asscalar(E const &expr);
1420

1521
DEFINE_FUNCTOR(pythonic::numpy, asscalar);
1622
}

pythran/pythonic/include/types/complex.hpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,30 @@
55

66
namespace std
77
{
8-
std::complex<double> operator+(std::complex<double> self, long other);
9-
std::complex<double> operator+(long self, std::complex<double> other);
10-
std::complex<double> operator-(std::complex<double> self, long other);
11-
std::complex<double> operator-(long self, std::complex<double> other);
12-
std::complex<double> operator*(std::complex<double> self, long other);
13-
std::complex<double> operator*(long self, std::complex<double> other);
14-
std::complex<double> operator/(std::complex<double> self, long other);
15-
std::complex<double> operator/(long self, std::complex<double> other);
16-
bool operator==(std::complex<double> self, long other);
17-
bool operator==(long self, std::complex<double> other);
18-
bool operator!=(std::complex<double> self, long other);
19-
bool operator!=(long self, std::complex<double> other);
8+
template <class T>
9+
std::complex<T> operator+(std::complex<T> self, long other);
10+
template <class T>
11+
std::complex<T> operator+(long self, std::complex<T> other);
12+
template <class T>
13+
std::complex<T> operator-(std::complex<T> self, long other);
14+
template <class T>
15+
std::complex<T> operator-(long self, std::complex<T> other);
16+
template <class T>
17+
std::complex<T> operator*(std::complex<T> self, long other);
18+
template <class T>
19+
std::complex<T> operator*(long self, std::complex<T> other);
20+
template <class T>
21+
std::complex<T> operator/(std::complex<T> self, long other);
22+
template <class T>
23+
std::complex<T> operator/(long self, std::complex<T> other);
24+
template <class T>
25+
bool operator==(std::complex<T> self, long other);
26+
template <class T>
27+
bool operator==(long self, std::complex<T> other);
28+
template <class T>
29+
bool operator!=(std::complex<T> self, long other);
30+
template <class T>
31+
bool operator!=(long self, std::complex<T> other);
2032
template <class T>
2133
bool operator<(std::complex<T> self, std::complex<T> other);
2234
template <class T>
@@ -31,27 +43,32 @@ namespace std
3143
bool operator||(std::complex<T> self, std::complex<T> other);
3244
template <class T>
3345
bool operator!(std::complex<T> self);
46+
47+
template <class T>
48+
struct hash<std::complex<T>> {
49+
size_t operator()(std::complex<T> const &x) const;
50+
};
3451
}
3552

3653
PYTHONIC_NS_BEGIN
3754
namespace __builtin__
3855
{
39-
template <size_t AttributeID>
40-
double getattr(std::complex<double> const &self);
56+
template <size_t AttributeID, class T>
57+
T getattr(std::complex<T> const &self);
4158
}
4259
PYTHONIC_NS_END
4360

4461
/* for type inference { */
4562

4663
#include "pythonic/include/types/combined.hpp"
47-
template <class K>
48-
struct __combined<indexable<K>, std::complex<double>> {
49-
using type = std::complex<double>;
64+
template <class K, class T>
65+
struct __combined<indexable<K>, std::complex<T>> {
66+
using type = std::complex<T>;
5067
};
5168

52-
template <class K>
53-
struct __combined<std::complex<double>, indexable<K>> {
54-
using type = std::complex<double>;
69+
template <class K, class T>
70+
struct __combined<std::complex<T>, indexable<K>> {
71+
using type = std::complex<T>;
5572
};
5673

5774
/* } */

pythran/pythonic/include/types/float.hpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@
44
#include "pythonic/include/types/attr.hpp"
55
#include <cstddef>
66

7-
PYTHONIC_NS_BEGIN
8-
namespace __builtin__
9-
{
10-
template <size_t AttributeID>
11-
double getattr(double self);
12-
}
13-
PYTHONIC_NS_END
147
#ifdef ENABLE_PYTHON_MODULE
158

169
#include "pythonic/python/core.hpp"

pythran/pythonic/include/types/int.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
#ifndef PYTHONIC_INCLUDE_TYPES_INT_HPP
22
#define PYTHONIC_INCLUDE_TYPES_INT_HPP
33

4+
PYTHONIC_NS_BEGIN
5+
namespace __builtin__
6+
{
7+
template <size_t AttributeID, class T>
8+
typename std::enable_if<std::is_integral<T>::value, T>::value getattr(T self);
9+
}
10+
PYTHONIC_NS_END
411
#ifdef ENABLE_PYTHON_MODULE
512

613
#include "pythonic/python/core.hpp"
14+
#include "pythonic/include/types/attr.hpp"
715

816
PYTHONIC_NS_BEGIN
917

@@ -45,6 +53,7 @@ PYTHONIC_INT_FROM_PYTHON(unsigned long long);
4553
PYTHONIC_INT_FROM_PYTHON(signed long long);
4654

4755
#undef PYTHONIC_INT_FROM_PYTHON
56+
4857
PYTHONIC_NS_END
4958
#endif
5059

pythran/pythonic/numpy/asscalar.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ PYTHONIC_NS_BEGIN
1313
namespace numpy
1414
{
1515
template <class E>
16-
typename E::dtype asscalar(E const &expr)
16+
asscalar_result_type<typename E::dtype> asscalar(E const &expr)
1717
{
1818
if (expr.flat_size() != 1)
1919
throw types::ValueError(

pythran/pythonic/types/complex.hpp

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,64 +7,76 @@
77

88
namespace std
99
{
10-
std::complex<double> operator+(std::complex<double> self, long other)
10+
template <class T>
11+
std::complex<T> operator+(std::complex<T> self, long other)
1112
{
12-
return self + double(other);
13+
return self + T(other);
1314
}
1415

15-
std::complex<double> operator+(long self, std::complex<double> other)
16+
template <class T>
17+
std::complex<T> operator+(long self, std::complex<T> other)
1618
{
17-
return double(self) + other;
19+
return T(self) + other;
1820
}
1921

20-
std::complex<double> operator-(std::complex<double> self, long other)
22+
template <class T>
23+
std::complex<T> operator-(std::complex<T> self, long other)
2124
{
22-
return self - double(other);
25+
return self - T(other);
2326
}
2427

25-
std::complex<double> operator-(long self, std::complex<double> other)
28+
template <class T>
29+
std::complex<T> operator-(long self, std::complex<T> other)
2630
{
27-
return double(self) - other;
31+
return T(self) - other;
2832
}
2933

30-
std::complex<double> operator*(std::complex<double> self, long other)
34+
template <class T>
35+
std::complex<T> operator*(std::complex<T> self, long other)
3136
{
32-
return self * double(other);
37+
return self * T(other);
3338
}
3439

35-
std::complex<double> operator*(long self, std::complex<double> other)
40+
template <class T>
41+
std::complex<T> operator*(long self, std::complex<T> other)
3642
{
37-
return double(self) * other;
43+
return T(self) * other;
3844
}
3945

40-
std::complex<double> operator/(std::complex<double> self, long other)
46+
template <class T>
47+
std::complex<T> operator/(std::complex<T> self, long other)
4148
{
42-
return self / double(other);
49+
return self / T(other);
4350
}
4451

45-
std::complex<double> operator/(long self, std::complex<double> other)
52+
template <class T>
53+
std::complex<T> operator/(long self, std::complex<T> other)
4654
{
47-
return double(self) / other;
55+
return T(self) / other;
4856
}
4957

50-
bool operator==(std::complex<double> self, long other)
58+
template <class T>
59+
bool operator==(std::complex<T> self, long other)
5160
{
52-
return self == double(other);
61+
return self == T(other);
5362
}
5463

55-
bool operator==(long self, std::complex<double> other)
64+
template <class T>
65+
bool operator==(long self, std::complex<T> other)
5666
{
57-
return double(self) == other;
67+
return T(self) == other;
5868
}
5969

60-
bool operator!=(std::complex<double> self, long other)
70+
template <class T>
71+
bool operator!=(std::complex<T> self, long other)
6172
{
62-
return self != double(other);
73+
return self != T(other);
6374
}
6475

65-
bool operator!=(long self, std::complex<double> other)
76+
template <class T>
77+
bool operator!=(long self, std::complex<T> other)
6678
{
67-
return double(self) != other;
79+
return T(self) != other;
6880
}
6981

7082
template <class T>
@@ -111,15 +123,20 @@ namespace std
111123
{
112124
return !self.real() && !self.imag();
113125
}
126+
template <class T>
127+
size_t hash<std::complex<T>>::operator()(std::complex<T> const &x) const
128+
{
129+
return std::hash<T>{}(x.real()) ^ std::hash<T>{}(x.imag());
130+
};
114131
}
115132

116133
PYTHONIC_NS_BEGIN
117134

118135
namespace __builtin__
119136
{
120137

121-
template <size_t AttributeID>
122-
double getattr(std::complex<double> const &self)
138+
template <size_t AttributeID, class T>
139+
T getattr(std::complex<T> const &self)
123140
{
124141
return AttributeID == pythonic::types::attr::REAL ? std::real(self)
125142
: std::imag(self);
@@ -142,36 +159,57 @@ PyObject *to_python<std::complex<long double>>::convert(
142159
PyArray_DescrFromType(NPY_CLONGDOUBLE), nullptr);
143160
}
144161

145-
template <class T>
146-
PyObject *to_python<std::complex<T>>::convert(std::complex<T> const &c)
162+
template <>
163+
PyObject *
164+
to_python<std::complex<double>>::convert(std::complex<double> const &c)
147165
{
148166
return PyComplex_FromDoubles(c.real(), c.imag());
149167
}
150168

169+
template <>
170+
PyObject *to_python<std::complex<float>>::convert(std::complex<float> const &c)
171+
{
172+
return PyArray_Scalar(const_cast<std::complex<float> *>(&c),
173+
PyArray_DescrFromType(NPY_CFLOAT), nullptr);
174+
}
175+
151176
template <>
152177
bool from_python<std::complex<long double>>::is_convertible(PyObject *obj)
153178
{
154-
return PyComplex_Check(obj) || PyArray_IsScalar(obj, CLongDouble);
179+
return PyArray_IsScalar(obj, CLongDouble);
155180
}
156181

157-
template <class T>
158-
bool from_python<std::complex<T>>::is_convertible(PyObject *obj)
182+
template <>
183+
bool from_python<std::complex<double>>::is_convertible(PyObject *obj)
159184
{
160185
return PyComplex_Check(obj);
161186
}
162-
template <class T>
163-
std::complex<T> from_python<std::complex<T>>::convert(PyObject *obj)
187+
188+
template <>
189+
bool from_python<std::complex<float>>::is_convertible(PyObject *obj)
190+
{
191+
return PyArray_IsScalar(obj, CFloat);
192+
}
193+
194+
template <>
195+
std::complex<long double>
196+
from_python<std::complex<long double>>::convert(PyObject *obj)
197+
{
198+
auto val = PyArrayScalar_VAL(obj, CLongDouble);
199+
return {val.real, val.imag};
200+
}
201+
202+
template <>
203+
std::complex<double> from_python<std::complex<double>>::convert(PyObject *obj)
204+
{
205+
return {PyComplex_RealAsDouble(obj), PyComplex_ImagAsDouble(obj)};
206+
}
207+
208+
template <>
209+
std::complex<float> from_python<std::complex<float>>::convert(PyObject *obj)
164210
{
165-
if (PyArray_IsScalar(obj, CLongDouble)) {
166-
auto val = PyArrayScalar_VAL(obj, CLongDouble);
167-
return {static_cast<T>(val.real), static_cast<T>(val.imag)};
168-
}
169-
if (PyComplex_Check(obj))
170-
return {PyComplex_RealAsDouble(obj), PyComplex_ImagAsDouble(obj)};
171-
else if (PyFloat_Check(obj))
172-
return {PyFloat_AsDouble(obj), 0.};
173-
else
174-
return {(double)PyInt_AsLong(obj), 0.};
211+
auto val = PyArrayScalar_VAL(obj, CFloat);
212+
return {val.real, val.imag};
175213
}
176214
PYTHONIC_NS_END
177215
#endif

0 commit comments

Comments
 (0)