r2rs-nmath 0.1.1

Statistics programming for Rust based on R's nmath package
Documentation
// Mathlib : A C Library of Special Functions
// Copyright (C) 2013-2022 The R Core Team
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

use num_traits::Float;

/// (pi * x).cos()
///
/// Exact when x = k/2 for all integer k
pub fn cospi(mut x: f64) -> f64 {
    /* NaNs propagated correctly */
    if x.is_nan() {
        return x;
    } // .cos() symmetric; (pi(x + 2k)).cos() == pi x.cos() for all integer k
    if !x.is_finite() {
        return f64::nan();
    }
    x = x.abs() % 2.0;
    if x % 1.0 == 0.5 {
        return 0.0;
    }
    if x == 1.0 {
        return -1.0;
    }
    if x == 0.0 {
        return 1.0;
    }
    // otherwise
    (std::f64::consts::PI * x).cos()
}

/// (pi * x).sin()
///
/// Exact when x = k/2 for all integer k
pub fn sinpi(mut x: f64) -> f64 {
    if x.is_nan() {
        return x;
    } // (pi(x + 2k)).sin() == pi x.sin()  for all integer k
    if !x.is_finite() {
        return f64::nan();
    }
    x %= 2.0;
    // map (-2,2) --> (-1,1] :
    if x <= -1.0 {
        x += 2.0
    } else if x > 1.0 {
        x -= 2.0
    }
    if x == 0.0 || x == 1.0 {
        return 0.0;
    }
    if x == 0.5 {
        return 1.0;
    }
    if x == -0.5 {
        return -1.0;
    }
    // otherwise
    (std::f64::consts::PI * x).sin()
}

/// (pi * x).tan()
///
/// Exact when x = k/4 for all integer k and half-values give NaN
pub fn tanpi(mut x: f64) -> f64 {
    if x.is_nan() {
        return x;
    } // (pi(x + k)).tan() == pi x.tan()  for all integer k
    if !x.is_finite() {
        return f64::nan();
    }
    x %= 1.0;
    // map (-1,1] --> (-1/2, 1/2] :
    if x <= -0.5 {
        x += 1.
    } else if x > 0.5 {
        x -= 1.
    }
    if x == 0.0 {
        0.0
    } else if x == 0.5 {
        f64::nan()
    } else if x == 0.25 {
        1.0
    } else if x == -0.25 {
        -1.0
    } else {
        (std::f64::consts::PI * x).tan()
    }
}