def diff(
    a: ndarray,
    n: int = 1,
    axis: int = -1,
    prepend: ndarray | None = None,
    append: ndarray | None = None,
) -> ndarray:
    """
    Calculate the n-th discrete difference along the given axis.
    The first difference is given by ``out[i] = a[i+1] - a[i]`` along
    the given axis, higher differences are calculated by using `diff`
    recursively.

    Parameters
    ----------
    a : array_like
        Input array
    n : int, optional
        The number of times values are differenced. If zero, the input
        is returned as-is.
    axis : int, optional
        The axis along which the difference is taken, default is the
        last axis.
    prepend, append : array_like, optional
        Values to prepend or append to `a` along axis prior to
        performing the difference.  Scalar values are expanded to
        arrays with length 1 in the direction of axis and the shape
        of the input array in along all other axes.  Otherwise the
        dimension and shape must match `a` except along axis.

    Returns
    -------
    diff : ndarray
        The n-th differences. The shape of the output is the same as `a`
        except along `axis` where the dimension is smaller by `n`. The
        type of the output is the same as the type of the difference
        between any two elements of `a`. This is the same as the type of
        `a` in most cases.

    See Also
    --------
    numpy.diff

    Notes
    -----
    Type is preserved for boolean arrays, so the result will contain
    `False` when consecutive elements are the same and `True` when they
    differ.

    For unsigned integer arrays, the results will also be unsigned. This
    should not be surprising, as the result is consistent with
    calculating the difference directly::

        >>> u8_arr = np.array([1, 0], dtype=np.uint8)
        >>> np.diff(u8_arr)
        array([255], dtype=uint8)
        >>> u8_arr[1,...] - u8_arr[0,...]
        255
        If this is not desirable, then the array should be cast to a larger
        integer type first:
        >>> i16_arr = u8_arr.astype(np.int16)
        >>> np.diff(i16_arr)
        array([-1], dtype=int16)
        Examples
        --------
        >>> x = np.array([1, 2, 4, 7, 0])
        >>> np.diff(x)
        array([ 1,  2,  3, -7])
        >>> np.diff(x, n=2)
        array([  1,   1, -10])
        >>> x = np.array([[1, 3, 6, 10], [0, 5, 6, 8]])
        >>> np.diff(x)
        array([[2, 3, 4],
            [5, 1, 2]])
        >>> np.diff(x, axis=0)
        array([[-1,  2,  0, -2]])

    Availability
    --------
    Multiple GPUs, Multiple CPUs
    """
    if n == 0:
        return a
    if n < 0:
        raise ValueError("order must be non-negative but got " + repr(n))

    nd = a.ndim
    if nd == 0:
        raise ValueError(
            "diff requires input that is at least one dimensional"
        )
    axis = normalize_axis_index(axis, nd)

    combined = []
    if prepend is not None:
        if prepend.ndim == 0:
            shape = list(a.shape)
            shape[axis] = 1
            prepend = broadcast_to(prepend, tuple(shape))
        combined.append(prepend)

    combined.append(a)

    if append is not None:
        if append.ndim == 0:
            shape = list(a.shape)
            shape[axis] = 1
            append = broadcast_to(append, tuple(shape))
        combined.append(append)

    if len(combined) > 1:
        a = concatenate(combined, axis)

    # Diffing with n > shape results in an empty array. We have
    # to handle this case explicitly as our slicing routines raise
    # an exception with out-of-bounds slices, while NumPy's dont.
    if a.shape[axis] <= n:
        shape = list(a.shape)
        shape[axis] = 0
        return empty(shape=tuple(shape), dtype=a.dtype)

    slice1l = [slice(None)] * nd
    slice2l = [slice(None)] * nd
    slice1l[axis] = slice(1, None)
    slice2l[axis] = slice(None, -1)
    slice1 = tuple(slice1l)
    slice2 = tuple(slice2l)

    op = not_equal if a.dtype == bool else subtract
    for _ in range(n):
        a = op(a[slice1], a[slice2])

    return a

    Calculate the n-th discrete difference along the given axis.
    The first difference is given by ``out[i] = a[i+1] - a[i]`` along
    the given axis, higher differences are calculated by using `diff`
    recursively.

    Parameters
    ----------
    a : array_like
        Input array
    n : int, optional
        The number of times values are differenced. If zero, the input
        is returned as-is.
    axis : int, optional
        The axis along which the difference is taken, default is the
        last axis.
    prepend, append : array_like, optional
        Values to prepend or append to `a` along axis prior to
        performing the difference.  Scalar values are expanded to
        arrays with length 1 in the direction of axis and the shape
        of the input array in along all other axes.  Otherwise the
        dimension and shape must match `a` except along axis.

    Returns
    -------
    diff : ndarray
        The n-th differences. The shape of the output is the same as `a`
        except along `axis` where the dimension is smaller by `n`. The
        type of the output is the same as the type of the difference
        between any two elements of `a`. This is the same as the type of
        `a` in most cases.

    See Also
    --------
    numpy.diff

    Notes
    -----
    Type is preserved for boolean arrays, so the result will contain
    `False` when consecutive elements are the same and `True` when they
    differ.

    For unsigned integer arrays, the results will also be unsigned. This
    should not be surprising, as the result is consistent with
    calculating the difference directly::

        >>> u8_arr = np.array([1, 0], dtype=np.uint8)
        >>> np.diff(u8_arr)
        array([255], dtype=uint8)
        >>> u8_arr[1,...] - u8_arr[0,...]
        255
        If this is not desirable, then the array should be cast to a larger
        integer type first:
        >>> i16_arr = u8_arr.astype(np.int16)
        >>> np.diff(i16_arr)
        array([-1], dtype=int16)
        Examples
        --------
        >>> x = np.array([1, 2, 4, 7, 0])
        >>> np.diff(x)
        array([ 1,  2,  3, -7])
        >>> np.diff(x, n=2)
        array([  1,   1, -10])
        >>> x = np.array([[1, 3, 6, 10], [0, 5, 6, 8]])
        >>> np.diff(x)
        array([[2, 3, 4],
            [5, 1, 2]])
        >>> np.diff(x, axis=0)
        array([[-1,  2,  0, -2]])

    Availability
    --------
    Multiple GPUs, Multiple CPUs
    
cupynumeric/_module/math_sum_prod_diff.py