pxfm/rounding/
ceil.rs

1/*
2 * // Copyright (c) Radzivon Bartoshyk 9/2025. All rights reserved.
3 * //
4 * // Redistribution and use in source and binary forms, with or without modification,
5 * // are permitted provided that the following conditions are met:
6 * //
7 * // 1.  Redistributions of source code must retain the above copyright notice, this
8 * // list of conditions and the following disclaimer.
9 * //
10 * // 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * // this list of conditions and the following disclaimer in the documentation
12 * // and/or other materials provided with the distribution.
13 * //
14 * // 3.  Neither the name of the copyright holder nor the names of its
15 * // contributors may be used to endorse or promote products derived from
16 * // this software without specific prior written permission.
17 * //
18 * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#[inline]
31pub const fn ceilf(x: f32) -> f32 {
32    /* Use generic implementation.  */
33    let mut i0: i32 = x.to_bits() as i32;
34    let j0 = ((i0 >> 23) & 0xff) - 0x7f;
35    if j0 < 23 {
36        if j0 < 0 {
37            /* return 0 * sign (x) if |x| < 1  */
38            if i0 < 0 {
39                i0 = 0x80000000u32 as i32;
40            } else if i0 != 0 {
41                i0 = 0x3f800000u32 as i32;
42            }
43        } else {
44            let i = (0x007fffff) >> j0;
45            if (i0 & i) == 0 {
46                return x; /* x is integral  */
47            }
48            if i0 > 0 {
49                i0 = i0.wrapping_add((0x00800000) >> j0);
50            }
51            i0 &= !i;
52        }
53    } else {
54        return if j0 == 0x80 {
55            x + x /* inf or NaN  */
56        } else {
57            x /* x is integral  */
58        };
59    }
60    f32::from_bits(i0 as u32)
61}
62
63#[inline]
64pub const fn ceil(x: f64) -> f64 {
65    let mut i0: i64 = x.to_bits() as i64;
66    let j0: i32 = (((i0 >> 52) & 0x7ff) - 0x3ff) as i32;
67    if j0 <= 51 {
68        if j0 < 0 {
69            /* return 0 * sign(x) if |x| < 1  */
70            if i0 < 0 {
71                i0 = 0x8000000000000000u64 as i64;
72            } else if i0 != 0 {
73                i0 = 0x3ff0000000000000u64 as i64;
74            }
75        } else {
76            let i = (0x000fffffffffffffu64 as i64) >> j0;
77            if (i0 & i) == 0 {
78                return x; /* x is integral  */
79            }
80            if i0 > 0 {
81                i0 = i0.wrapping_add((0x0010000000000000u64 >> j0) as i64);
82            }
83            i0 &= !i;
84        }
85    } else {
86        return if j0 == 0x400 {
87            x + x /* inf or NaN  */
88        } else {
89            x /* x is integral  */
90        };
91    }
92    f64::from_bits(i0 as u64)
93}
94
95pub(crate) trait CpuCeil {
96    fn cpu_ceil(self) -> Self;
97}
98
99impl CpuCeil for f32 {
100    #[inline]
101    fn cpu_ceil(self) -> Self {
102        #[cfg(any(
103            all(
104                any(target_arch = "x86", target_arch = "x86_64"),
105                target_feature = "sse4.1"
106            ),
107            target_arch = "aarch64"
108        ))]
109        {
110            self.ceil()
111        }
112        #[cfg(not(any(
113            all(
114                any(target_arch = "x86", target_arch = "x86_64"),
115                target_feature = "sse4.1"
116            ),
117            target_arch = "aarch64"
118        )))]
119        {
120            ceilf(self)
121        }
122    }
123}
124
125impl CpuCeil for f64 {
126    #[inline]
127    fn cpu_ceil(self) -> Self {
128        #[cfg(any(
129            all(
130                any(target_arch = "x86", target_arch = "x86_64"),
131                target_feature = "sse4.1"
132            ),
133            target_arch = "aarch64"
134        ))]
135        {
136            self.ceil()
137        }
138        #[cfg(not(any(
139            all(
140                any(target_arch = "x86", target_arch = "x86_64"),
141                target_feature = "sse4.1"
142            ),
143            target_arch = "aarch64"
144        )))]
145        {
146            ceil(self)
147        }
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154
155    #[test]
156    fn test_ceilf() {
157        assert_eq!(ceilf(0.0), 0.0);
158        assert_eq!(ceilf(10.0), 10.0);
159        assert_eq!(ceilf(10.1), 11.0);
160        assert_eq!(ceilf(-9.0), -9.0);
161        assert_eq!(ceilf(-9.5), -9.0);
162    }
163
164    #[test]
165    fn test_ceil() {
166        assert_eq!(ceil(0.0), 0.0);
167        assert_eq!(ceil(10.0), 10.0);
168        assert_eq!(ceil(10.1), 11.0);
169        assert_eq!(ceil(-9.0), -9.0);
170        assert_eq!(ceil(-9.5), -9.0);
171    }
172}