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}