1use core::fmt;
12
13use crate::float::{
14 EXPONENT_BIAS, EXPONENT_MAX, EXPONENT_SHIFT, FRACTION_BITS, Float128, QUIET_BIT, SIGN_MASK,
15};
16
17#[derive(Debug, Clone, Copy, PartialEq)]
23pub struct Inexact<T> {
24 pub rounded: T,
26 pub source: Float128,
28}
29
30impl<T> fmt::Display for Inexact<T> {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 write!(
33 f,
34 "the binary128 value 0x{:032x} does not fit the destination type exactly",
35 self.source.to_bits()
36 )
37 }
38}
39
40impl<T: fmt::Debug> core::error::Error for Inexact<T> {}
41
42impl Float128 {
45 #[must_use]
48 pub fn from_f64(value: f64) -> Self {
49 let bits = value.to_bits();
50 let negative = bits >> 63 != 0;
51 let biased = ((bits >> 52) & 0x7ff) as u32;
52 let fraction = u128::from(bits & 0x000f_ffff_ffff_ffff);
53 widen(negative, biased, fraction, 11, 52)
54 }
55
56 #[must_use]
58 pub fn from_f32(value: f32) -> Self {
59 let bits = value.to_bits();
60 let negative = bits >> 31 != 0;
61 let biased = (bits >> 23) & 0xff;
62 let fraction = u128::from(bits & 0x007f_ffff);
63 widen(negative, biased, fraction, 8, 23)
64 }
65
66 #[must_use]
69 pub fn from_i128_rounded(value: i128) -> Self {
70 let negative = value < 0;
71 let magnitude = value.unsigned_abs();
72 Self::from_parts_rounded(negative, magnitude, 0).0
73 }
74
75 #[must_use]
78 pub fn from_u128_rounded(value: u128) -> Self {
79 Self::from_parts_rounded(false, value, 0).0
80 }
81
82 pub fn try_from_i128(value: i128) -> Result<Self, Inexact<Self>> {
88 let negative = value < 0;
89 let (rounded, lost) = Self::from_parts_rounded(negative, value.unsigned_abs(), 0);
90 if lost {
91 Err(Inexact {
92 rounded,
93 source: rounded,
94 })
95 } else {
96 Ok(rounded)
97 }
98 }
99
100 pub fn try_from_u128(value: u128) -> Result<Self, Inexact<Self>> {
106 let (rounded, lost) = Self::from_parts_rounded(false, value, 0);
107 if lost {
108 Err(Inexact {
109 rounded,
110 source: rounded,
111 })
112 } else {
113 Ok(rounded)
114 }
115 }
116}
117
118fn widen(
125 negative: bool,
126 biased: u32,
127 fraction: u128,
128 exponent_bits: u32,
129 fraction_bits: u32,
130) -> Float128 {
131 let sign = u128::from(negative) << (FRACTION_BITS + 15);
132 let source_max = (1u32 << exponent_bits) - 1;
133 let source_bias = (1i32 << (exponent_bits - 1)) - 1;
134 let shift = FRACTION_BITS - fraction_bits;
135
136 if biased == source_max {
137 let bits = sign | ((EXPONENT_MAX as u128) << EXPONENT_SHIFT) | (fraction << shift);
142 return Float128::from_bits(bits);
143 }
144 if biased == 0 {
145 if fraction == 0 {
146 return Float128::from_bits(sign);
147 }
148 let exponent = 1 - source_bias - fraction_bits as i32;
150 let (value, lost) = Float128::from_parts_rounded(negative, fraction, exponent);
151 debug_assert!(!lost, "widening a narrower binary format is always exact");
152 return value;
153 }
154 let biased128 = biased as i32 - source_bias + EXPONENT_BIAS;
155 let bits = sign | ((biased128 as u128) << EXPONENT_SHIFT) | (fraction << shift);
156 Float128::from_bits(bits)
157}
158
159impl Float128 {
162 #[must_use]
168 pub fn to_f64_rounded(self) -> f64 {
169 self.narrow_f64().0
170 }
171
172 pub fn to_f64(self) -> Result<f64, Inexact<f64>> {
180 let (rounded, lost) = self.narrow_f64();
181 if lost {
182 Err(Inexact {
183 rounded,
184 source: self,
185 })
186 } else {
187 Ok(rounded)
188 }
189 }
190
191 #[must_use]
193 pub fn to_f32_rounded(self) -> f32 {
194 self.narrow_f32().0
195 }
196
197 pub fn to_f32(self) -> Result<f32, Inexact<f32>> {
202 let (rounded, lost) = self.narrow_f32();
203 if lost {
204 Err(Inexact {
205 rounded,
206 source: self,
207 })
208 } else {
209 Ok(rounded)
210 }
211 }
212
213 fn narrow_f64(self) -> (f64, bool) {
215 let (bits, lost) = self.narrow(11, 52);
216 (f64::from_bits(bits as u64), lost)
217 }
218
219 fn narrow_f32(self) -> (f32, bool) {
221 let (bits, lost) = self.narrow(8, 23);
222 (f32::from_bits(bits as u32), lost)
223 }
224
225 fn narrow(self, exponent_bits: u32, fraction_bits: u32) -> (u128, bool) {
228 let target_max = (1u32 << exponent_bits) - 1;
229 let target_bias = (1i32 << (exponent_bits - 1)) - 1;
230 let sign = u128::from(self.is_sign_negative()) << (exponent_bits + fraction_bits);
231 let shift = FRACTION_BITS - fraction_bits;
232
233 if self.is_nan() {
234 let mut payload = self.fraction() >> shift;
245 if payload == 0 {
246 payload = 1;
247 }
248 let bits = sign | (u128::from(target_max) << fraction_bits) | payload;
249 return (bits, self.fraction() & ((1u128 << shift) - 1) != 0);
250 }
251 if self.is_infinite() {
252 return (sign | (u128::from(target_max) << fraction_bits), false);
253 }
254 let Some((_, significand, exponent)) = self.decompose() else {
255 return (sign, false);
256 };
257 if significand == 0 {
258 return (sign, false);
259 }
260
261 let leading = 127 - significand.leading_zeros();
264 let mut exponent = exponent + leading as i32;
265 let target_exponent = exponent + target_bias;
266 if target_exponent >= target_max as i32 {
267 let bits = sign | (u128::from(target_max) << fraction_bits);
268 return (bits, true);
269 }
270
271 let lost;
272 let mut fraction;
273 if target_exponent <= 0 {
274 let drop = leading as i32 - fraction_bits as i32 + (1 - target_exponent);
280 let drop = drop.max(0).unsigned_abs();
281 let (rounded, dropped) = crate::float::round_shift_right(significand, drop);
282 let bits = sign | rounded;
285 return (bits, dropped);
286 } else if leading > fraction_bits {
287 let drop = leading - fraction_bits;
288 let (rounded, dropped) = crate::float::round_shift_right(significand, drop);
289 lost = dropped;
290 fraction = rounded;
291 if fraction >> fraction_bits > 1 {
292 fraction >>= 1;
293 exponent += 1;
294 }
295 } else {
296 fraction = significand << (fraction_bits - leading);
297 lost = false;
298 }
299
300 let target_exponent = exponent + target_bias;
301 if target_exponent >= target_max as i32 {
302 let bits = sign | (u128::from(target_max) << fraction_bits);
303 return (bits, true);
304 }
305 let bits = sign
306 | ((target_exponent as u128) << fraction_bits)
307 | (fraction & ((1u128 << fraction_bits) - 1));
308 (bits, lost)
309 }
310}
311
312impl Float128 {
315 pub fn to_i128(self) -> Result<i128, Inexact<i128>> {
323 let (value, exact) = self.trunc_i128();
324 if exact {
325 Ok(value)
326 } else {
327 Err(Inexact {
328 rounded: value,
329 source: self,
330 })
331 }
332 }
333
334 pub fn to_i64(self) -> Result<i64, Inexact<i64>> {
339 match self.to_i128() {
340 Ok(wide) => i64::try_from(wide).map_err(|_| Inexact {
341 rounded: if wide < 0 { i64::MIN } else { i64::MAX },
342 source: self,
343 }),
344 Err(inexact) => Err(Inexact {
345 rounded: i64::try_from(inexact.rounded).unwrap_or(if inexact.rounded < 0 {
346 i64::MIN
347 } else {
348 i64::MAX
349 }),
350 source: self,
351 }),
352 }
353 }
354
355 fn trunc_i128(self) -> (i128, bool) {
357 if self.is_nan() {
358 return (0, false);
359 }
360 if self.is_infinite() {
361 return (
362 if self.is_sign_negative() {
363 i128::MIN
364 } else {
365 i128::MAX
366 },
367 false,
368 );
369 }
370 let Some((negative, significand, exponent)) = self.decompose() else {
371 return (0, false);
372 };
373 if significand == 0 {
374 return (0, true);
375 }
376 let leading = 127 - significand.leading_zeros();
377 let magnitude_bits = leading as i32 + exponent + 1;
378 let limit = if negative { 128 } else { 127 };
380 if magnitude_bits > limit {
381 return (if negative { i128::MIN } else { i128::MAX }, false);
382 }
383 let (magnitude, fractional) = if exponent >= 0 {
384 let shift = exponent.unsigned_abs();
387 if shift >= 128 {
388 return (if negative { i128::MIN } else { i128::MAX }, false);
389 }
390 (significand << shift, false)
391 } else {
392 let shift = exponent.unsigned_abs();
394 if shift >= 128 {
395 (0, true)
396 } else {
397 (
398 significand >> shift,
399 significand & ((1u128 << shift) - 1) != 0,
400 )
401 }
402 };
403 let signed = if negative {
404 magnitude.wrapping_neg() as i128
405 } else {
406 magnitude as i128
407 };
408 (signed, !fractional)
409 }
410}
411
412impl From<f64> for Float128 {
413 fn from(value: f64) -> Self {
414 Self::from_f64(value)
415 }
416}
417
418impl From<f32> for Float128 {
419 fn from(value: f32) -> Self {
420 Self::from_f32(value)
421 }
422}
423
424impl TryFrom<Float128> for f64 {
425 type Error = Inexact<f64>;
426
427 fn try_from(value: Float128) -> Result<Self, Self::Error> {
428 value.to_f64()
429 }
430}
431
432impl TryFrom<Float128> for f32 {
433 type Error = Inexact<f32>;
434
435 fn try_from(value: Float128) -> Result<Self, Self::Error> {
436 value.to_f32()
437 }
438}
439
440impl Float128 {
441 #[must_use]
448 pub const fn quiet_nan(payload: u128) -> Self {
449 let fraction = (payload & (QUIET_BIT - 1)) | QUIET_BIT;
450 Self::from_bits(((EXPONENT_MAX as u128) << EXPONENT_SHIFT) | fraction)
451 }
452
453 #[must_use]
455 pub const fn neg_quiet_nan(payload: u128) -> Self {
456 Self::from_bits(Self::quiet_nan(payload).to_bits() | SIGN_MASK)
457 }
458}