1#[inline]
31pub const fn roundf(x: f32) -> f32 {
32 let mut i0 = x.to_bits() as i32;
33 let j0 = ((i0 >> 23) & 0xff) - 0x7f;
34 if j0 < 23 {
35 if j0 < 0 {
36 i0 &= 0x80000000u32 as i32;
37 if j0 == -1 {
38 i0 |= 0x3f800000;
39 }
40 } else {
41 let i = 0x007fffff >> j0;
42 if (i0 & i) == 0 {
43 return x;
45 }
46
47 i0 += 0x00400000 >> j0;
48 i0 &= !i;
49 }
50 } else {
51 return if j0 == 0x80 {
52 x + x
54 } else {
55 x
56 };
57 }
58 f32::from_bits(i0 as u32)
59}
60
61#[inline]
63pub(crate) fn froundf_finite(x: f32) -> f32 {
64 #[cfg(any(
65 all(
66 any(target_arch = "x86", target_arch = "x86_64"),
67 target_feature = "sse4.1"
68 ),
69 target_arch = "aarch64"
70 ))]
71 {
72 x.round()
73 }
74 #[cfg(not(any(
75 all(
76 any(target_arch = "x86", target_arch = "x86_64"),
77 target_feature = "sse4.1"
78 ),
79 target_arch = "aarch64"
80 )))]
81 {
82 roundf(x)
83 }
84}
85
86#[inline]
87pub const fn round(x: f64) -> f64 {
88 let mut i0: i64 = x.to_bits() as i64;
89 let j0: i32 = (((i0 >> 52) & 0x7ff) - 0x3ff) as i32;
90 if j0 < 52 {
91 if j0 < 0 {
92 i0 &= 0x8000000000000000u64 as i64;
93 if j0 == -1 {
94 i0 |= 0x3ff0000000000000u64 as i64;
95 }
96 } else {
97 let i = (0x000fffffffffffffu64 >> j0) as i64;
98 if (i0 & i) == 0 {
99 return x;
101 }
102
103 i0 += (0x0008000000000000u64 >> j0) as i64;
104 i0 &= !i;
105 }
106 } else {
107 return if j0 == 0x400 {
108 x + x
110 } else {
111 x
112 };
113 }
114 f64::from_bits(i0 as u64)
115}
116
117#[inline]
119pub(crate) fn fround_finite(x: f64) -> f64 {
120 #[cfg(any(
121 all(
122 any(target_arch = "x86", target_arch = "x86_64"),
123 target_feature = "sse4.1"
124 ),
125 target_arch = "aarch64"
126 ))]
127 {
128 x.round()
129 }
130 #[cfg(not(any(
131 all(
132 any(target_arch = "x86", target_arch = "x86_64"),
133 target_feature = "sse4.1"
134 ),
135 target_arch = "aarch64"
136 )))]
137 {
138 round(x)
139 }
140}
141
142pub(crate) trait CpuRound {
143 fn cpu_round(self) -> Self;
144}
145
146impl CpuRound for f32 {
147 #[inline]
148 fn cpu_round(self) -> Self {
149 froundf_finite(self)
150 }
151}
152
153impl CpuRound for f64 {
154 #[inline]
155 fn cpu_round(self) -> Self {
156 fround_finite(self)
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_roundf() {
166 assert_eq!(roundf(0f32), 0.0f32.round());
167 assert_eq!(roundf(1f32), 1.0f32.round());
168 assert_eq!(roundf(1.2f32), 1.2f32.round());
169 assert_eq!(roundf(-1.2f32), (-1.2f32).round());
170 assert_eq!(roundf(-1.6f32), (-1.6f32).round());
171 assert_eq!(roundf(-1.5f32), (-1.5f32).round());
172 assert_eq!(roundf(1.6f32), 1.6f32.round());
173 assert_eq!(roundf(1.5f32), 1.5f32.round());
174 assert_eq!(roundf(2.5f32), 2.5f32.round());
175 }
176
177 #[test]
178 fn test_round() {
179 assert_eq!(round(0.), 0.0f64.round());
180 assert_eq!(round(1.), 1.0f64.round());
181 assert_eq!(round(1.2), 1.2f64.round());
182 assert_eq!(round(-1.2), (-1.2f64).round());
183 assert_eq!(round(-1.6), (-1.6f64).round());
184 assert_eq!(round(-1.5), (-1.5f64).round());
185 assert_eq!(round(1.6), 1.6f64.round());
186 assert_eq!(round(1.5), 1.5f64.round());
187 assert_eq!(round(2.5), 2.5f64.round());
188 }
189}