You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
3.1 KiB
97 lines
3.1 KiB
//
|
|
// 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 <georg@steffers.org>
|
|
//
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
//
|
|
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<Fractional> =
|
|
(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<Fractional> =
|
|
(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),
|
|
}
|
|
}
|