// // Some trigonometic functions with Fractions results. // Currently only sin and cos are implemented. As I was unable // to find a really good integral approximation for them I // implement them as tables which are predefined using the // floating point function f64::sin and then transformed into // a fraction of a given PRECISION. // // Georg Hopp // // Copyright © 2019 Georg Hopp // // 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 3 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. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // use crate::{Fractional}; pub const PI :Fractional = Fractional(355, 113); // This is a really close // fractional approximation // for pi const PRECISION :i64 = 100000; #[inline] pub fn rad(d: u32) -> f64 { use std::f64::consts::PI; d as f64 * PI / 180.0 } pub fn sin(d: i32) -> Fractional { // hold sin Fractionals from 0 to 89 ... lazy_static::lazy_static! { static ref SINTAB :Vec = (0..90).map(|x| _sin(x)).collect(); } // fractional sin from f64 sin. (From 1° to 89°) fn _sin(d: u32) -> Fractional { match d { 0 => Fractional(0, 1), _ => { // This is undefined behaviour for very large f64, but our f64 // is always between 0.0 and 10000.0 which should be fine. let s = (f64::sin(rad(d)) * PRECISION as f64).round() as i64; Fractional(s, PRECISION).reduce() } } } match d { 90 => Fractional(1, 1), 180 => SINTAB[0], 270 => -Fractional(1, 1), 1..=89 => SINTAB[d as usize], 91..=179 => SINTAB[180 - d as usize], 181..=269 => -SINTAB[d as usize - 180], 271..=359 => -SINTAB[360 - d as usize], _ => sin(d % 360), } } pub fn cos(d: i32) -> Fractional { lazy_static::lazy_static! { static ref COSTAB :Vec = (0..90).map(|x| _cos(x)).collect(); } fn _cos(d: u32) -> Fractional { match d { 0 => Fractional(1, 1), _ => { let s = (f64::cos(rad(d)) * PRECISION as f64).round() as i64; Fractional(s, PRECISION).reduce() } } } match d { 90 | 270 => Fractional(0, 1), 180 => -COSTAB[0], 1..=89 => COSTAB[d as usize], 91..=179 => -COSTAB[180 - d as usize], 181..=269 => -COSTAB[d as usize - 180], 271..=359 => COSTAB[360 - d as usize], _ => cos(d % 360), } }