Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add complex number support to cosh #453

Merged
merged 3 commits into from
Jul 7, 2022
Merged

Add complex number support to cosh #453

merged 3 commits into from
Jul 7, 2022

Conversation

kgryte
Copy link
Contributor

@kgryte kgryte commented Jun 13, 2022

This PR

  • adds complex number support to cosh by documenting special cases. The hyperbolic cosine is an entire function in the complex plane. Thus, the function has no branch cuts.
  • updates the input and output array data types to be any floating-point data type, not just real-valued floating-point data types.
  • derives special cases from C99 and tested against NumPy (script found below).
import numpy as np
import math

def is_equal_float(x, y):
    """Test whether two floating-point numbers are equal with special consideration for zeros and NaNs.

    Parameters
    ----------
    x : float
        First input number.
    y : float
        Second input number.

    Returns
    -------
    bool
        Boolean indicating whether two floating-point numbers are equal.

    Examples
    --------
    >>> is_equal_float(0.0, -0.0)
    False
    >>> is_equal_float(-0.0, -0.0)
    True
    """
    # Handle +-0:
    if x == 0.0 and y == 0.0:
        return math.copysign(1.0, x) == math.copysign(1.0, y)

    # Handle NaNs:
    if x != x:
        return y != y

    # Everything else, including infinities:
    return x == y


def is_equal(x, y):
    """Test whether two complex numbers are equal with special consideration for zeros and NaNs.

    Parameters
    ----------
    x : complex
        First input number.
    y : complex
        Second input number.

    Returns
    -------
    bool
        Boolean indicating whether two complex numbers are equal.

    Examples
    --------
    >>> import numpy as np
    >>> is_equal(complex(np.nan, np.nan), complex(np.nan, np.nan))
    True
    """
    return is_equal_float(x.real, y.real) and is_equal_float(x.imag, y.imag)


# Strided array consisting of input values and expected values:
values = [
    complex(0.0, 0.0),        # 0
    complex(1.0, 0.0),        # 0
    
    complex(-0.0, 0.0),       # 1
    complex(1.0, -0.0),       # 1
    
    complex(0.0, np.inf),     # 2
    complex(np.nan, 0),       # 2
    
    complex(0.0, np.nan),     # 3
    complex(np.nan, 0.0),     # 3
    
    complex(1.0, np.inf),     # 4
    complex(np.nan, np.nan),  # 4
    
    complex(1.0, np.nan),     # 5
    complex(np.nan, np.nan),  # 5
    
    complex(np.inf, 0.0),     # 6
    complex(np.inf, 0.0),     # 6
    
    complex(np.inf, -0.0),    # 7
    complex(np.inf, -0.0),    # 7
    
    complex(np.inf, 1.0),     # 8
    complex(np.inf, np.inf),  # 8
    
    complex(np.inf, np.inf),  # 9
    complex(np.inf, np.nan),  # 9
    
    complex(np.inf, np.nan),  # 10
    complex(np.inf, np.nan),  # 10
    
    complex(np.nan, 0.0),     # 11
    complex(np.nan, 0.0),     # 11
    
    complex(np.nan, 1.0),     # 12
    complex(np.nan, np.nan),  # 12

    complex(np.nan, 1.0),     # 13
    complex(np.nan, np.nan),  # 13
    
    complex(np.nan, np.nan),  # 14
    complex(np.nan, np.nan)   # 14
]

for i in range(len(values)//2):
    j = i * 2
    v = values[j]
    e = values[j+1]
    actual = np.cosh(v)
    print('Value: {value}'.format(value=str(v)))
    print('Actual: {actual}'.format(actual=str(actual)))
    print('Expected: {expected}'.format(expected=str(e)))
    print('Equal: {is_equal}'.format(is_equal=str(is_equal(actual, e))))
    print('\n')
Value: 0j
Actual: (1+0j)
Expected: (1+0j)
Equal: True


Value: (-0+0j)
Actual: (1-0j)
Expected: (1-0j)
Equal: True


/path/to/ccosh.py:116: RuntimeWarning: invalid value encountered in cosh
  actual = np.cosh(v)
Value: infj
Actual: (nan+0j)
Expected: (nan+0j)
Equal: True


Value: nanj
Actual: (nan+0j)
Expected: (nan+0j)
Equal: True


Value: (1+infj)
Actual: (nan+nanj)
Expected: (nan+nanj)
Equal: True


Value: (1+nanj)
Actual: (nan+nanj)
Expected: (nan+nanj)
Equal: True


Value: (inf+0j)
Actual: (inf+0j)
Expected: (inf+0j)
Equal: True


Value: (inf-0j)
Actual: (inf-0j)
Expected: (inf-0j)
Equal: True


Value: (inf+1j)
Actual: (inf+infj)
Expected: (inf+infj)
Equal: True


Value: (inf+infj)
Actual: (inf+nanj)
Expected: (inf+nanj)
Equal: True


Value: (inf+nanj)
Actual: (inf+nanj)
Expected: (inf+nanj)
Equal: True


Value: (nan+0j)
Actual: (nan+0j)
Expected: (nan+0j)
Equal: True


Value: (nan+1j)
Actual: (nan+nanj)
Expected: (nan+nanj)
Equal: True


Value: (nan+1j)
Actual: (nan+nanj)
Expected: (nan+nanj)
Equal: True


Value: (nan+nanj)
Actual: (nan+nanj)
Expected: (nan+nanj)
Equal: True

@kgryte kgryte added API extension Adds new functions or objects to the API. topic: Complex Data Types Complex number data types. labels Jun 13, 2022
@kgryte kgryte added this to the v2022 milestone Jun 13, 2022
@kgryte kgryte added API change Changes to existing functions or objects in the API. and removed API extension Adds new functions or objects to the API. labels Jun 20, 2022
@kgryte
Copy link
Contributor Author

kgryte commented Jul 7, 2022

As cosh does not involve branch cuts and the special cases introduced in this PR follow prior art, will merge. Further revisions can be addressed in subsequent PRs...

@kgryte kgryte merged commit b43dcb1 into main Jul 7, 2022
@kgryte kgryte deleted the cmplx-cosh branch July 7, 2022 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API change Changes to existing functions or objects in the API. topic: Complex Data Types Complex number data types.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant