Repository: cupy/cupy

Issue:
poly1d with int64 arrays -- unexpected output
### Description

Hi there, I've found unexpected behaviour when fitting a polynomial using an int64 array. 

It seems that a polynomial created with `p = cp.poly1d(cp.polyfit(x, y, N))` requires a float array `x` when calling via `p(x)`  -- see code example below. The output of `cp.polyfit` looks the same so `poly1d` seems to be the culprit.

(I also note that Numpy has introduced a new `polynomial.Polynomial` for fitting, so this issue may not be high priority). Thanks!

### To Reproduce

```py
import pylab as plt
import cupy as cp

# create x values using arange, default dtype is int64
x = cp.arange(1048576) - 1048576//2

# Create example polynomial to fit
x_ = x.astype('float64')
y = x_ + 0.5 * x_**2 - 0.05 * x_**3 + 0.001 * x_**4 - 0.00001 * x_**5

# Fit the polynomial
p = cp.poly1d(cp.polyfit(x, y, 5))

# Plot polynomials
plt.plot(cp.asnumpy(y))
plt.plot(cp.asnumpy(p(x_)))
plt.plot(cp.asnumpy(p(x)))

print(p(x).dtype) # prints float64 (not int64!)
print(p(x_).dtype) # also prints float64

assert np.allclose(p(x_), p(x)) # will raise an error

```

![image](https://user-images.githubusercontent.com/713251/163835045-d12b136d-6318-48ad-8f20-35bcc11de6c8.png)


### Installation

Conda-Forge (`conda install ...`)

### Environment

```
(base) dancpr@blc00:~$ python -c 'import cupy; cupy.show_config()'
OS                           : Linux-4.15.0-120-generic-x86_64-with-glibc2.23
Python Version               : 3.9.5
CuPy Version                 : 9.6.0
CuPy Platform                : NVIDIA CUDA
NumPy Version                : 1.20.3
SciPy Version                : 1.7.3
Cython Build Version         : 0.29.24
Cython Runtime Version       : 0.29.24
CUDA Root                    : /opt/conda
nvcc PATH                    : /opt/conda/bin/nvcc
CUDA Build Version           : 11020
CUDA Driver Version          : 11010
CUDA Runtime Version         : 11050
cuBLAS Version               : (available)
cuFFT Version                : 10600
cuRAND Version               : 10206
cuSOLVER Version             : (11, 2, 1)
cuSPARSE Version             : (available)
NVRTC Version                : (11, 5)
Thrust Version               : 101000
CUB Build Version            : 101000
Jitify Build Version         : 65946d2
cuDNN Build Version          : None
cuDNN Version                : None
NCCL Build Version           : None
NCCL Runtime Version         : None
cuTENSOR Version             : 10303
cuSPARSELt Build Version     : None
Device 0 Name                : GeForce GTX 1080 Ti
Device 0 Compute Capability  : 61
Device 0 PCI Bus ID          : 0000:82:00.0
```


### Additional Information

_No response_


Discussion:
@telegraphic Thanks for your reporting! This bug looks to be caused by an int64 overflow.

Resolving patch:
diff --git a/cupy/lib/_routines_poly.py b/cupy/lib/_routines_poly.py
--- a/cupy/lib/_routines_poly.py
+++ b/cupy/lib/_routines_poly.py
@@ -255,34 +255,22 @@ def polyval(p, x):
     """
     if isinstance(p, cupy.poly1d):
         p = p.coeffs
+    if isinstance(x, cupy.poly1d):
+        x = x.coeffs
     if not isinstance(p, cupy.ndarray) or p.ndim == 0:
-        raise TypeError('p can be 1d ndarray or poly1d object only')
-    if p.ndim != 1:
-        # to be consistent with polyarithmetic routines' behavior of
-        # not allowing multidimensional polynomial inputs.
-        raise ValueError('p can be 1d ndarray or poly1d object only')
-        # TODO(Dahlia-Chehata): Support poly1d x
-    if (isinstance(x, cupy.ndarray) and x.ndim <= 1) or numpy.isscalar(x):
-        val = cupy.asarray(x).reshape(-1, 1)
-    else:
-        raise NotImplementedError(
-            'poly1d or non 1d values are not currently supported')
-    out = p[::-1] * cupy.power(val, cupy.arange(p.size))
-    out = out.sum(axis=1)
-    dtype = cupy.result_type(p, val)
-    if cupy.isscalar(x) or x.ndim == 0:
-        return out.astype(dtype, copy=False).reshape()
-    if p.dtype == numpy.complex128 and val.dtype in [
-       numpy.float16, numpy.float32, numpy.complex64]:
-        return out.astype(numpy.complex64, copy=False)
-    p_kind_score = numpy.dtype(p.dtype.char.lower()).kind
-    x_kind_score = numpy.dtype(val.dtype.char.lower()).kind
-    if (p.dtype.kind not in 'c' and (p_kind_score == x_kind_score
-                                     or val.dtype.kind in 'c')) or (
-            issubclass(p.dtype.type, numpy.integer)
-            and issubclass(val.dtype.type, numpy.floating)):
-        return out.astype(val.dtype, copy=False)
-    return out.astype(dtype, copy=False)
+        raise TypeError('p must be 1d ndarray or poly1d object')
+    if p.ndim > 1:
+        raise ValueError('p must be 1d array')
+    dtype = numpy.result_type(p.dtype.type(0), x)
+    p = p.astype(dtype, copy=False)
+    if p.size == 0:
+        return cupy.zeros(x.shape, dtype)
+    if dtype == numpy.bool_:
+        return p.any() * x + p[-1]
+    if not cupy.isscalar(x):
+        x = cupy.asarray(x, dtype=dtype)[..., None]
+    x = x ** cupy.arange(p.size, dtype=dtype)
+    return (p[::-1] * x).sum(axis=-1, dtype=dtype)
 
 
 def roots(p):


Test patch:
diff --git a/tests/cupy_tests/lib_tests/test_polynomial.py b/tests/cupy_tests/lib_tests/test_polynomial.py
--- a/tests/cupy_tests/lib_tests/test_polynomial.py
+++ b/tests/cupy_tests/lib_tests/test_polynomial.py
@@ -728,14 +728,14 @@ class TestPolyvalDtypesCombination:
     @testing.numpy_cupy_allclose(rtol=1e-6)
     def test_polyval_diff_types_array_array(self, xp, dtype1, dtype2):
         a = testing.shaped_arange((10,), xp, dtype1)
-        b = testing.shaped_arange((5,), xp, dtype2)
+        b = testing.shaped_arange((3,), xp, dtype2)
         return xp.polyval(a, b)
 
     @testing.for_all_dtypes_combination(names=['dtype1', 'dtype2'], full=True)
     @testing.numpy_cupy_allclose(rtol=1e-6)
     def test_polyval_diff_types_array_scalar(self, xp, dtype1, dtype2):
         a = testing.shaped_arange((10,), xp, dtype1)
-        b = dtype2(5)
+        b = dtype2(3)
         return xp.polyval(a, b)
 
 
@@ -744,18 +744,16 @@ class TestPolyvalNotImplemented:
 
     @testing.for_all_dtypes()
     def test_polyval_ndim_values(self, dtype):
-        a = testing.shaped_arange((2, ), cupy, dtype)
+        a = testing.shaped_arange((10,), cupy, dtype)
         b = testing.shaped_arange((2, 4), cupy, dtype)
-        with pytest.raises(NotImplementedError):
-            cupy.polyval(a, b)
+        return cupy.polyval(a, b)
 
     @testing.for_all_dtypes()
     def test_polyval_poly1d_values(self, dtype):
         a = testing.shaped_arange((5,), cupy, dtype)
         b = testing.shaped_arange((3,), cupy, dtype)
         b = cupy.poly1d(b)
-        with pytest.raises(NotImplementedError):
-            cupy.polyval(a, b)
+        return cupy.polyval(a, b)
 
 
 @testing.gpu