taz/
lib.rs

1//! Taz
2//!
3//! Taz is Rust library to evaluate a mathematical expression.
4//!
5
6mod expression;
7mod token;
8
9/// Evaluate a mathematical expression.
10///
11/// If error occurs during evaluation, an error message is stored in string contained in Result output.
12/// Otherwise, the Result output contains the value of evaluation stored in 64-bits float.
13///
14/// # Example of simple expression
15/// ```
16/// use taz;
17///
18/// let expression: String = String::from("2.0 * (4.43 - 5.99) / 3.0");
19///
20/// let result: Result<f64, String> = taz::evaluate(expression.as_str());
21/// assert!(result.is_ok());
22///
23/// match result {
24///     Ok(value) => println!("{expression} = {value}"),
25///     Err(message) => println!("Error occured: {message}")
26/// }
27/// ```
28///
29/// # Example of expression containing predefined constants and function
30/// ```
31/// use taz;
32///
33/// let expression: String = String::from("cos(pi / 4.0)^2 + sin(pi / 4.0)^2");
34///
35/// let result: Result<f64, String> = taz::evaluate(expression.as_str());
36/// assert!(result.is_ok());
37///
38/// match result {
39///     Ok(value) => println!("{expression} = {value}"),
40///     Err(message) => println!("Error occured: {message}")
41/// }
42///
43/// ```
44pub fn evaluate(raw_expression: &str) -> Result<f64, String> {
45    let expression = expression::Expression::new(raw_expression);
46    return expression.infix().postfix().evaluate();
47}
48
49/// Units tests
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    fn relative_error(value: f64, reference: f64) -> f64 {
55        if reference == 0.0 {
56            return value.abs();
57        } else {
58            return (value - reference).abs() / reference.abs();
59        }
60    }
61
62    #[test]
63    fn test_evaluation_expression_with_numbers_binary_operator() {
64        let expression: String = String::from("43.75 - 20.97");
65        let reference: f64 = 43.75 - 20.97;
66
67        match evaluate(expression.as_str()) {
68            Ok(result) => assert!(relative_error(result, reference) < 0.01),
69            Err(_) => assert!(false),
70        }
71    }
72
73    #[test]
74    fn test_evaluation_expresion_with_numbers_operators() {
75        let expression: String = String::from("-43.75 + 20.97");
76        let reference: f64 = -43.75 + 20.97;
77
78        match evaluate(expression.as_str()) {
79            Ok(result) => {
80                println!("Evaluation = {}", result);
81                println!("Reference = {}", reference);
82                assert!(relative_error(result, reference) < 0.01);
83            }
84            Err(_) => assert!(false),
85        }
86    }
87
88    #[test]
89    fn test_evaluation_expression_with_numbers_operators_parenthesis() {
90        let expression: String = String::from("43.75 + (-20.97 / 2.87) * 3.14");
91        let reference: f64 = 43.75 + (-20.97 / 2.87) * 3.14;
92
93        match evaluate(expression.as_str()) {
94            Ok(result) => assert!(relative_error(result, reference) < 0.01),
95            Err(_) => assert!(false),
96        }
97    }
98
99    #[test]
100    fn test_evaluation_expression_with_function_and_number() {
101        let expression: String = String::from("sqrt(9.0)");
102        let reference: f64 = 3.0;
103
104        match evaluate(expression.as_str()) {
105            Ok(result) => assert!(relative_error(result, reference) < 0.01),
106            Err(_) => assert!(false),
107        }
108    }
109
110    #[test]
111    fn test_evaluation_expression_with_constant_and_number() {
112        let expression: String = String::from("pi / 2.0");
113        let reference: f64 = std::f64::consts::PI / 2.0;
114
115        match evaluate(expression.as_str()) {
116            Ok(result) => assert!(relative_error(result, reference) < 0.01),
117            Err(_) => assert!(false),
118        }
119    }
120
121    #[test]
122    fn test_evaluation_expression_with_all() {
123        let expression: String = String::from("sin(2.0 - pi) * cos((-pi + 2.0) / 2.0)");
124        let reference: f64 =
125            (2.0 - std::f64::consts::PI).sin() * ((-std::f64::consts::PI + 2.0) / 2.0).cos();
126
127        match evaluate(expression.as_str()) {
128            Ok(result) => assert!(relative_error(result, reference) < 0.01),
129            Err(_) => assert!(false),
130        }
131    }
132}