injective_math/fp_decimal/
trigonometry.rs1use crate::fp_decimal::FPDecimal;
2
3impl FPDecimal {
4 pub(self) fn _cos(mut x: FPDecimal) -> FPDecimal {
5 x = FPDecimal::_change_range(x);
6 FPDecimal::_sin(FPDecimal::PI / FPDecimal::TWO - x)
7 }
8
9 fn _sine_taylor_expansion(x: FPDecimal) -> FPDecimal {
10 x - (x.pow(FPDecimal::THREE).unwrap() / FPDecimal::THREE.factorial()) + (x.pow(FPDecimal::FIVE).unwrap() / FPDecimal::FIVE.factorial())
11 - (x.pow(FPDecimal::SEVEN).unwrap() / FPDecimal::SEVEN.factorial())
12 + (x.pow(FPDecimal::NINE).unwrap() / FPDecimal::NINE.factorial())
13 - (x.pow(FPDecimal::ELEVEN).unwrap() / (FPDecimal::ELEVEN).factorial())
14 + (x.pow(FPDecimal::THREE + FPDecimal::TEN).unwrap() / (FPDecimal::THREE + FPDecimal::TEN).factorial())
15 }
16
17 pub(self) fn _sin(mut x: FPDecimal) -> FPDecimal {
18 x = FPDecimal::_change_range(x);
19 let pi_by_2 = FPDecimal::PI / FPDecimal::TWO;
20 let pi_plus_pi_by_2 = FPDecimal::PI + FPDecimal::PI / FPDecimal::TWO;
21
22 if (FPDecimal::ZERO == x) || (FPDecimal::PI == x) {
23 return FPDecimal::ZERO;
24 }
25
26 if pi_by_2 == x {
27 return FPDecimal::ONE;
28 }
29
30 if pi_plus_pi_by_2 == x {
31 return FPDecimal::ZERO - FPDecimal::ONE;
32 }
33
34 if FPDecimal::ZERO < x && x < pi_by_2 {
35 return FPDecimal::_sine_taylor_expansion(x);
36 }
37
38 if pi_by_2 < x && x < FPDecimal::PI {
39 return FPDecimal::_sine_taylor_expansion(FPDecimal::PI - x);
40 }
41
42 if FPDecimal::PI < x && x < pi_plus_pi_by_2 {
43 let mut output = FPDecimal::_sine_taylor_expansion(x - FPDecimal::PI);
44 output.sign = 0;
45 return output;
46 }
47
48 let mut output = FPDecimal::_sine_taylor_expansion(FPDecimal::PI * FPDecimal::TWO - x);
49 output.sign = 0;
50 output
51 }
52
53 fn _change_range(x: FPDecimal) -> FPDecimal {
54 if x.is_zero() {
55 return x;
56 }
57 let mut output = x;
58 let two_pi = FPDecimal::PI * FPDecimal::TWO;
59 match x < FPDecimal::ZERO {
60 true => {
61 while output < FPDecimal::ZERO {
62 output += two_pi;
63 }
64 }
65 false => {
66 while output > two_pi {
67 output -= two_pi;
68 }
69 }
70 }
71 output
72 }
73
74 pub fn imprecise_cos(&self) -> FPDecimal {
75 FPDecimal::_cos(*self)
76 }
77
78 pub fn imprecise_sin(&self) -> FPDecimal {
79 FPDecimal::_sin(*self)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use crate::FPDecimal;
86 use std::str::FromStr;
87 fn almost_eq(x: FPDecimal, target: FPDecimal) {
88 assert!(((x - target) / x).abs() <= FPDecimal::from_str("0.01").unwrap());
89 }
90
91 #[test]
92 fn test_cosine_zero() {
93 assert_eq!(FPDecimal::ZERO.imprecise_cos(), FPDecimal::ONE);
94 }
95
96 #[test]
97 fn test_cosine_one() {
98 almost_eq(FPDecimal::ONE.imprecise_cos(), FPDecimal::from_str("0.54030230586").unwrap());
99 }
100
101 #[test]
102 fn test_cosine_negative_one() {
103 almost_eq(
104 (FPDecimal::ZERO - FPDecimal::ONE).imprecise_cos(),
105 FPDecimal::from_str("0.54030230586").unwrap(),
106 );
107 }
108
109 #[test]
110 fn test_sine_zero() {
111 assert_eq!(FPDecimal::ZERO.imprecise_sin(), FPDecimal::ZERO);
112 }
113
114 #[test]
115 fn test_sine_one() {
116 almost_eq(FPDecimal::ONE.imprecise_sin(), FPDecimal::from_str("0.8414709848").unwrap());
118 }
119
120 #[test]
121 fn test_sine_negative_one() {
122 almost_eq((-FPDecimal::ONE).imprecise_sin(), FPDecimal::from_str("-0.8414709848").unwrap());
123 }
124}