Skip to main content

temperature_convert/
lib.rs

1#![no_std]
2cfg_if! {
3    if #[cfg(feature = "std")] {
4        extern crate std;
5    } else {
6        use num_traits::real::Real;
7    }
8}
9use cfg_if::cfg_if;
10
11#[must_use]
12pub const fn kelvin_to_celsius(val: f64) -> f64 {
13    val - 273.15
14}
15
16#[must_use]
17pub fn kelvin_to_fahrenheit(val: f64) -> f64 {
18    cfg_if! {
19        if #[cfg(feature = "std")] {
20            f64::mul_add(val - 273.15, 9. / 5., 32.)
21        } else {
22            Real::mul_add(val - 273.15, 9. / 5., 32.)
23        }
24    }
25}
26
27#[must_use]
28pub const fn celsius_to_kelvin(val: f64) -> f64 {
29    val + 273.15
30}
31
32#[must_use]
33pub fn celsius_to_fahrenheit(val: f64) -> f64 {
34    cfg_if! {
35        if #[cfg(feature = "std")] {
36            f64::mul_add(val, 9. / 5., 32.)
37        } else {
38            Real::mul_add(val, 9. / 5., 32.)
39        }
40    }
41}
42
43#[must_use]
44pub fn fahrenheit_to_kelvin(val: f64) -> f64 {
45    cfg_if! {
46        if #[cfg(feature = "std")] {
47            f64::mul_add(val - 32., 5. / 9., 273.15)
48        } else {
49            Real::mul_add(val - 32., 5. / 9., 273.15)
50        }
51    }
52}
53
54#[must_use]
55pub const fn fahrenheit_to_celsius(val: f64) -> f64 {
56    (val - 32.) * (5. / 9.)
57}
58
59#[cfg(test)]
60mod temperature_tests {
61    use super::*;
62    use rstest::rstest;
63
64    const PRECISION: f64 = f64::EPSILON;
65
66    /// Helper function to compare f64 values within precision
67    fn approx_equal(x: f64, y: f64) -> bool {
68        (x - y).abs() < PRECISION
69    }
70
71    #[rstest]
72    #[case(0.0, -273.15)]
73    #[case(100.0, -173.14999999999998)]
74    #[case(1000.0, 726.85)]
75    #[case(5000.0, 4726.85)]
76    fn test_kelvin_to_celsius_precision(#[case] kelvin_val: f64, #[case] celsius_val: f64) {
77        let converted = kelvin_to_celsius(kelvin_val);
78        assert!(
79            approx_equal(converted, celsius_val),
80            "High precision K->C failed - Expected: {celsius_val}, Got: {converted}"
81        );
82    }
83
84    #[rstest]
85    #[case(0.0, -459.66999999999996)]
86    #[case(100.0, -279.66999999999996)]
87    #[case(1000.0, 1340.3300000000002)]
88    #[case(5000.0, 8540.330000000002)]
89    #[case(69420.0, 124496.33000000002)]
90    fn test_kelvin_to_fahrenheit_precision(#[case] kelvin_val: f64, #[case] fahrenheit_val: f64) {
91        let converted = kelvin_to_fahrenheit(kelvin_val);
92        assert!(
93            approx_equal(converted, fahrenheit_val),
94            "High precision K->F failed - Expected: {fahrenheit_val}, Got: {converted}"
95        );
96    }
97
98    #[rstest]
99    #[case(0.0, 273.15)]
100    #[case(100.0, 373.15)]
101    #[case(1000.0, 1273.15)]
102    #[case(5000.0, 5273.15)]
103    #[case(69420.0, 69693.15)]
104    fn test_celsius_to_kelvin_precision(#[case] celsius_val: f64, #[case] kelvin_val: f64) {
105        let converted = celsius_to_kelvin(celsius_val);
106        assert!(
107            approx_equal(converted, kelvin_val),
108            "High precision C->K failed - Expected: {kelvin_val}, Got: {converted}"
109        );
110    }
111
112    #[rstest]
113    #[case(0.0, 32.0)]
114    #[case(100.0, 212.0)]
115    #[case(1000.0, 1832.0)]
116    #[case(5000.0, 9032.0)]
117    #[case(69420.0, 124988.0)]
118    fn test_celsius_to_fahrenheit_precision(#[case] celsius_val: f64, #[case] fahrenheit_val: f64) {
119        let converted = celsius_to_fahrenheit(celsius_val);
120        assert!(
121            approx_equal(converted, fahrenheit_val),
122            "High precision C->F failed - Expected: {fahrenheit_val}, Got: {converted}"
123        );
124    }
125
126    #[rstest]
127    #[case(0.0, 255.3722222222222)]
128    #[case(100.0, 310.92777777777775)]
129    #[case(1000.0, 810.9277777777778)]
130    #[case(5000.0, 3033.15)]
131    #[case(69420.0, 38822.03888888889)]
132    fn test_fahrenheit_to_kelvin_precision(#[case] fahrenheit_val: f64, #[case] kelvin_val: f64) {
133        let converted = fahrenheit_to_kelvin(fahrenheit_val);
134        assert!(
135            approx_equal(converted, kelvin_val),
136            "High precision F->K failed - Expected: {kelvin_val}, Got: {converted}"
137        );
138    }
139
140    #[rstest]
141    #[case(0.0, -17.77777777777778)]
142    #[case(100.0, 37.77777777777778)]
143    #[case(1000.0, 537.7777777777778)]
144    #[case(5000.0, 2760.0)]
145    #[case(69420.0, 38548.88888888889)]
146    fn test_fahrenheit_to_celsius_precision(#[case] fahrenheit_val: f64, #[case] celsius_val: f64) {
147        let converted = fahrenheit_to_celsius(fahrenheit_val);
148        assert!(
149            approx_equal(converted, celsius_val),
150            "High precision F->C failed - Expected: {celsius_val}, Got: {converted}"
151        );
152    }
153}