1 //! Defines rounding schemes for floating-point numbers. 2 3 use crate::util::*; 4 use super::float::ExtendedFloat; 5 use super::mantissa::Mantissa; 6 use super::shift::*; 7 8 // GENERIC 9 // ------- 10 11 // NEAREST ROUNDING 12 13 // Shift right N-bytes and round to the nearest. 14 // 15 // Return if we are above halfway and if we are halfway. 16 perftools_inline!{ 17 pub(crate) fn round_nearest<M>(fp: &mut ExtendedFloat<M>, shift: i32) 18 -> (bool, bool) 19 where M: Mantissa 20 { 21 // Extract the truncated bits using mask. 22 // Calculate if the value of the truncated bits are either above 23 // the mid-way point, or equal to it. 24 // 25 // For example, for 4 truncated bytes, the mask would be b1111 26 // and the midway point would be b1000. 27 let mask: M = lower_n_mask(as_cast(shift)); 28 let halfway: M = lower_n_halfway(as_cast(shift)); 29 30 let truncated_bits = fp.mant & mask; 31 let is_above = truncated_bits > halfway; 32 let is_halfway = truncated_bits == halfway; 33 34 // Bit shift so the leading bit is in the hidden bit. 35 overflowing_shr(fp, shift); 36 37 (is_above, is_halfway) 38 }} 39 40 // Tie rounded floating point to event. 41 perftools_inline!{ 42 pub(crate) fn tie_even<M>(fp: &mut ExtendedFloat<M>, is_above: bool, is_halfway: bool) 43 where M: Mantissa 44 { 45 // Extract the last bit after shifting (and determine if it is odd). 46 let is_odd = fp.mant & M::ONE == M::ONE; 47 48 // Calculate if we need to roundup. 49 // We need to roundup if we are above halfway, or if we are odd 50 // and at half-way (need to tie-to-even). 51 if is_above || (is_odd && is_halfway) { 52 fp.mant += M::ONE; 53 } 54 }} 55 56 // Shift right N-bytes and round nearest, tie-to-even. 57 // 58 // Floating-point arithmetic uses round to nearest, ties to even, 59 // which rounds to the nearest value, if the value is halfway in between, 60 // round to an even value. 61 perftools_inline!{ 62 pub(crate) fn round_nearest_tie_even<M>(fp: &mut ExtendedFloat<M>, shift: i32) 63 where M: Mantissa 64 { 65 let (is_above, is_halfway) = round_nearest(fp, shift); 66 tie_even(fp, is_above, is_halfway); 67 }} 68 69 // Tie rounded floating point away from zero. 70 perftools_inline!{ 71 pub(crate) fn tie_away_zero<M>(fp: &mut ExtendedFloat<M>, is_above: bool, is_halfway: bool) 72 where M: Mantissa 73 { 74 // Calculate if we need to roundup. 75 // We need to roundup if we are halfway or above halfway, 76 // since the value is always positive and we need to round away 77 // from zero. 78 if is_above || is_halfway { 79 fp.mant += M::ONE; 80 } 81 }} 82 83 // Shift right N-bytes and round nearest, tie-away-zero. 84 // 85 // Floating-point arithmetic defines round to nearest, ties away from zero, 86 // which rounds to the nearest value, if the value is halfway in between, 87 // ties away from zero. 88 perftools_inline!{ 89 pub(crate) fn round_nearest_tie_away_zero<M>(fp: &mut ExtendedFloat<M>, shift: i32) 90 where M: Mantissa 91 { 92 let (is_above, is_halfway) = round_nearest(fp, shift); 93 tie_away_zero(fp, is_above, is_halfway); 94 }} 95 96 // DIRECTED ROUNDING 97 98 // Shift right N-bytes and round towards a direction. 99 // 100 // Return if we have any truncated bytes. 101 perftools_inline!{ 102 pub(crate) fn round_toward<M>(fp: &mut ExtendedFloat<M>, shift: i32) 103 -> bool 104 where M: Mantissa 105 { 106 let mask: M = lower_n_mask(as_cast(shift)); 107 let truncated_bits = fp.mant & mask; 108 109 // Bit shift so the leading bit is in the hidden bit. 110 overflowing_shr(fp, shift); 111 112 truncated_bits != M::ZERO 113 }} 114 115 // Round up. 116 perftools_inline!{ 117 pub(crate) fn upward<M>(fp: &mut ExtendedFloat<M>, is_truncated: bool) 118 where M: Mantissa 119 { 120 if is_truncated { 121 fp.mant += M::ONE; 122 } 123 }} 124 125 // Shift right N-bytes and round toward infinity. 126 // 127 // Floating-point arithmetic defines round toward infinity, which rounds 128 // towards positive infinity. 129 perftools_inline!{ 130 pub(crate) fn round_upward<M>(fp: &mut ExtendedFloat<M>, shift: i32) 131 where M: Mantissa 132 { 133 // If the truncated bits are non-zero, that is, any rounding error occurred, 134 // round-up. 135 let is_truncated = round_toward(fp, shift); 136 upward(fp, is_truncated); 137 }} 138 139 // Round down. 140 perftools_inline!{ 141 pub(crate) fn downard<M>(_: &mut ExtendedFloat<M>, _: bool) 142 where M: Mantissa 143 {}} 144 145 // Shift right N-bytes and round toward zero. 146 // 147 // Floating-point arithmetic defines round toward zero, which rounds 148 // towards positive zero. 149 perftools_inline!{ 150 pub(crate) fn round_downward<M>(fp: &mut ExtendedFloat<M>, shift: i32) 151 where M: Mantissa 152 { 153 // Bit shift so the leading bit is in the hidden bit. 154 // No rounding schemes, so we just ignore everything else. 155 let is_truncated = round_toward(fp, shift); 156 downard(fp, is_truncated); 157 }} 158 159 // NATIVE FLOAT 160 // ------------ 161 162 // FLOAT ROUNDING 163 164 /// Trait to round extended-precision floats to native representations. 165 pub trait FloatRounding<M: Mantissa>: Float { 166 /// Default number of bits to shift (or 64 - mantissa size - 1). 167 const DEFAULT_SHIFT: i32; 168 /// Mask to determine if a full-carry occurred (1 in bit above hidden bit). 169 const CARRY_MASK: M; 170 } 171 172 // Literals don't work for generic types, we need to use this as a hack. 173 macro_rules! float_rounding_f32 { 174 ($($t:tt)*) => ($( 175 impl FloatRounding<$t> for f32 { 176 const DEFAULT_SHIFT: i32 = $t::FULL - f32::MANTISSA_SIZE - 1; 177 const CARRY_MASK: $t = 0x1000000; 178 } 179 )*) 180 } 181 182 float_rounding_f32! { u64 u128 } 183 184 // Literals don't work for generic types, we need to use this as a hack. 185 macro_rules! float_rounding_f64 { 186 ($($t:tt)*) => ($( 187 impl FloatRounding<$t> for f64 { 188 const DEFAULT_SHIFT: i32 = $t::FULL - f64::MANTISSA_SIZE - 1; 189 const CARRY_MASK: $t = 0x20000000000000; 190 } 191 )*) 192 } 193 194 float_rounding_f64! { u64 u128 } 195 196 // ROUND TO FLOAT 197 198 // Shift the ExtendedFloat fraction to the fraction bits in a native float. 199 // 200 // Floating-point arithmetic uses round to nearest, ties to even, 201 // which rounds to the nearest value, if the value is halfway in between, 202 // round to an even value. 203 perftools_inline!{ 204 pub(crate) fn round_to_float<T, M, Cb>(fp: &mut ExtendedFloat<M>, cb: Cb) 205 where T: FloatRounding<M>, 206 M: Mantissa, 207 Cb: FnOnce(&mut ExtendedFloat<M>, i32) 208 { 209 // Calculate the difference to allow a single calculation 210 // rather than a loop, to minimize the number of ops required. 211 // This does underflow detection. 212 let final_exp = fp.exp + T::DEFAULT_SHIFT; 213 if final_exp < T::DENORMAL_EXPONENT { 214 // We would end up with a denormal exponent, try to round to more 215 // digits. Only shift right if we can avoid zeroing out the value, 216 // which requires the exponent diff to be < M::BITS. The value 217 // is already normalized, so we shouldn't have any issue zeroing 218 // out the value. 219 let diff = T::DENORMAL_EXPONENT - fp.exp; 220 if diff <= M::FULL { 221 // We can avoid underflow, can get a valid representation. 222 cb(fp, diff); 223 } else { 224 // Certain underflow, assign literal 0s. 225 fp.mant = M::ZERO; 226 fp.exp = 0; 227 } 228 } else { 229 cb(fp, T::DEFAULT_SHIFT); 230 } 231 232 if fp.mant & T::CARRY_MASK == T::CARRY_MASK { 233 // Roundup carried over to 1 past the hidden bit. 234 shr(fp, 1); 235 } 236 }} 237 238 // AVOID OVERFLOW/UNDERFLOW 239 240 // Avoid overflow for large values, shift left as needed. 241 // 242 // Shift until a 1-bit is in the hidden bit, if the mantissa is not 0. 243 perftools_inline!{ 244 pub(crate) fn avoid_overflow<T, M>(fp: &mut ExtendedFloat<M>) 245 where T: FloatRounding<M>, 246 M: Mantissa 247 { 248 // Calculate the difference to allow a single calculation 249 // rather than a loop, minimizing the number of ops required. 250 if fp.exp >= T::MAX_EXPONENT { 251 let diff = fp.exp - T::MAX_EXPONENT; 252 if diff <= T::MANTISSA_SIZE { 253 // Our overflow mask needs to start at the hidden bit, or at 254 // `T::MANTISSA_SIZE+1`, and needs to have `diff+1` bits set, 255 // to see if our value overflows. 256 let bit = as_cast(T::MANTISSA_SIZE+1); 257 let n = as_cast(diff+1); 258 let mask: M = internal_n_mask(bit, n); 259 if (fp.mant & mask).is_zero() { 260 // If we have no 1-bit in the hidden-bit position, 261 // which is index 0, we need to shift 1. 262 let shift = diff + 1; 263 shl(fp, shift); 264 } 265 } 266 } 267 }} 268 269 // ROUND TO NATIVE 270 271 // Round an extended-precision float to a native float representation. 272 perftools_inline!{ 273 pub(crate) fn round_to_native<T, M, Cb>(fp: &mut ExtendedFloat<M>, cb: Cb) 274 where T: FloatRounding<M>, 275 M: Mantissa, 276 Cb: FnOnce(&mut ExtendedFloat<M>, i32) 277 { 278 // Shift all the way left, to ensure a consistent representation. 279 // The following right-shifts do not work for a non-normalized number. 280 fp.normalize(); 281 282 // Round so the fraction is in a native mantissa representation, 283 // and avoid overflow/underflow. 284 round_to_float::<T, M, _>(fp, cb); 285 avoid_overflow::<T, M>(fp); 286 }} 287 288 // Get the rounding scheme to determine if we should go up or down. 289 perftools_inline!{ 290 #[allow(unused_variables)] 291 pub(crate) fn internal_rounding(kind: RoundingKind, sign: Sign) 292 -> RoundingKind 293 { 294 #[cfg(not(feature = "rounding"))] { 295 RoundingKind::NearestTieEven 296 } 297 298 #[cfg(feature = "rounding")] { 299 match sign { 300 Sign::Positive => { 301 match kind { 302 RoundingKind::TowardPositiveInfinity => RoundingKind::Upward, 303 RoundingKind::TowardNegativeInfinity => RoundingKind::Downward, 304 RoundingKind::TowardZero => RoundingKind::Downward, 305 _ => kind, 306 } 307 }, 308 Sign::Negative => { 309 match kind { 310 RoundingKind::TowardPositiveInfinity => RoundingKind::Downward, 311 RoundingKind::TowardNegativeInfinity => RoundingKind::Upward, 312 RoundingKind::TowardZero => RoundingKind::Downward, 313 _ => kind, 314 } 315 }, 316 } 317 } 318 }} 319 320 // Get the global, default rounding scheme. 321 perftools_inline!{ 322 #[cfg(feature = "correct")] 323 #[allow(unused_variables)] 324 pub(crate) fn global_rounding(sign: Sign) -> RoundingKind { 325 #[cfg(not(feature = "rounding"))] { 326 RoundingKind::NearestTieEven 327 } 328 329 #[cfg(feature = "rounding")] { 330 internal_rounding(get_float_rounding(), sign) 331 } 332 }} 333 334 // TESTS 335 // ----- 336 337 #[cfg(test)] 338 mod tests { 339 use crate::float::ExtendedFloat80; 340 use super::*; 341 342 // NEAREST ROUNDING 343 344 #[test] round_nearest_test()345 fn round_nearest_test() { 346 // Check exactly halfway (b'1100000') 347 let mut fp = ExtendedFloat80 { mant: 0x60, exp: 0 }; 348 let (above, halfway) = round_nearest(&mut fp, 6); 349 assert!(!above); 350 assert!(halfway); 351 assert_eq!(fp.mant, 1); 352 353 // Check above halfway (b'1100001') 354 let mut fp = ExtendedFloat80 { mant: 0x61, exp: 0 }; 355 let (above, halfway) = round_nearest(&mut fp, 6); 356 assert!(above); 357 assert!(!halfway); 358 assert_eq!(fp.mant, 1); 359 360 // Check below halfway (b'1011111') 361 let mut fp = ExtendedFloat80 { mant: 0x5F, exp: 0 }; 362 let (above, halfway) = round_nearest(&mut fp, 6); 363 assert!(!above); 364 assert!(!halfway); 365 assert_eq!(fp.mant, 1); 366 } 367 368 #[test] round_nearest_tie_even_test()369 fn round_nearest_tie_even_test() { 370 // Check round-up, halfway 371 let mut fp = ExtendedFloat80 { mant: 0x60, exp: 0 }; 372 round_nearest_tie_even(&mut fp, 6); 373 assert_eq!(fp.mant, 2); 374 375 // Check round-down, halfway 376 let mut fp = ExtendedFloat80 { mant: 0x20, exp: 0 }; 377 round_nearest_tie_even(&mut fp, 6); 378 assert_eq!(fp.mant, 0); 379 380 // Check round-up, above halfway 381 let mut fp = ExtendedFloat80 { mant: 0x61, exp: 0 }; 382 round_nearest_tie_even(&mut fp, 6); 383 assert_eq!(fp.mant, 2); 384 385 let mut fp = ExtendedFloat80 { mant: 0x21, exp: 0 }; 386 round_nearest_tie_even(&mut fp, 6); 387 assert_eq!(fp.mant, 1); 388 389 // Check round-down, below halfway 390 let mut fp = ExtendedFloat80 { mant: 0x5F, exp: 0 }; 391 round_nearest_tie_even(&mut fp, 6); 392 assert_eq!(fp.mant, 1); 393 394 let mut fp = ExtendedFloat80 { mant: 0x1F, exp: 0 }; 395 round_nearest_tie_even(&mut fp, 6); 396 assert_eq!(fp.mant, 0); 397 } 398 399 #[test] round_nearest_tie_away_zero_test()400 fn round_nearest_tie_away_zero_test() { 401 // Check round-up, halfway 402 let mut fp = ExtendedFloat80 { mant: 0x60, exp: 0 }; 403 round_nearest_tie_away_zero(&mut fp, 6); 404 assert_eq!(fp.mant, 2); 405 406 let mut fp = ExtendedFloat80 { mant: 0x20, exp: 0 }; 407 round_nearest_tie_away_zero(&mut fp, 6); 408 assert_eq!(fp.mant, 1); 409 410 // Check round-up, above halfway 411 let mut fp = ExtendedFloat80 { mant: 0x61, exp: 0 }; 412 round_nearest_tie_away_zero(&mut fp, 6); 413 assert_eq!(fp.mant, 2); 414 415 let mut fp = ExtendedFloat80 { mant: 0x21, exp: 0 }; 416 round_nearest_tie_away_zero(&mut fp, 6); 417 assert_eq!(fp.mant, 1); 418 419 // Check round-down, below halfway 420 let mut fp = ExtendedFloat80 { mant: 0x5F, exp: 0 }; 421 round_nearest_tie_away_zero(&mut fp, 6); 422 assert_eq!(fp.mant, 1); 423 424 let mut fp = ExtendedFloat80 { mant: 0x1F, exp: 0 }; 425 round_nearest_tie_away_zero(&mut fp, 6); 426 assert_eq!(fp.mant, 0); 427 } 428 429 // DIRECTED ROUNDING 430 431 #[test] round_upward_test()432 fn round_upward_test() { 433 // b0000000 434 let mut fp = ExtendedFloat80 { mant: 0x00, exp: 0 }; 435 round_upward(&mut fp, 6); 436 assert_eq!(fp.mant, 0); 437 438 // b1000000 439 let mut fp = ExtendedFloat80 { mant: 0x40, exp: 0 }; 440 round_upward(&mut fp, 6); 441 assert_eq!(fp.mant, 1); 442 443 // b1100000 444 let mut fp = ExtendedFloat80 { mant: 0x60, exp: 0 }; 445 round_upward(&mut fp, 6); 446 assert_eq!(fp.mant, 2); 447 448 // b1110000 449 let mut fp = ExtendedFloat80 { mant: 0x70, exp: 0 }; 450 round_upward(&mut fp, 6); 451 assert_eq!(fp.mant, 2); 452 } 453 454 #[test] round_downward_test()455 fn round_downward_test() { 456 // b0000000 457 let mut fp = ExtendedFloat80 { mant: 0x00, exp: 0 }; 458 round_downward(&mut fp, 6); 459 assert_eq!(fp.mant, 0); 460 461 // b1000000 462 let mut fp = ExtendedFloat80 { mant: 0x40, exp: 0 }; 463 round_downward(&mut fp, 6); 464 assert_eq!(fp.mant, 1); 465 466 // b1100000 467 let mut fp = ExtendedFloat80 { mant: 0x60, exp: 0 }; 468 round_downward(&mut fp, 6); 469 assert_eq!(fp.mant, 1); 470 471 // b1110000 472 let mut fp = ExtendedFloat80 { mant: 0x70, exp: 0 }; 473 round_downward(&mut fp, 6); 474 assert_eq!(fp.mant, 1); 475 } 476 477 // HIGH-LEVEL 478 479 #[test] round_to_float_test()480 fn round_to_float_test() { 481 // Denormal 482 let mut fp = ExtendedFloat80 { mant: 1<<63, exp: f64::DENORMAL_EXPONENT - 15 }; 483 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 484 assert_eq!(fp.mant, 1<<48); 485 assert_eq!(fp.exp, f64::DENORMAL_EXPONENT); 486 487 // Halfway, round-down (b'1000000000000000000000000000000000000000000000000000010000000000') 488 let mut fp = ExtendedFloat80 { mant: 0x8000000000000400, exp: -63 }; 489 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 490 assert_eq!(fp.mant, 1<<52); 491 assert_eq!(fp.exp, -52); 492 493 // Halfway, round-up (b'1000000000000000000000000000000000000000000000000000110000000000') 494 let mut fp = ExtendedFloat80 { mant: 0x8000000000000C00, exp: -63 }; 495 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 496 assert_eq!(fp.mant, (1<<52) + 2); 497 assert_eq!(fp.exp, -52); 498 499 // Above halfway 500 let mut fp = ExtendedFloat80 { mant: 0x8000000000000401, exp: -63 }; 501 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 502 assert_eq!(fp.mant, (1<<52)+1); 503 assert_eq!(fp.exp, -52); 504 505 let mut fp = ExtendedFloat80 { mant: 0x8000000000000C01, exp: -63 }; 506 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 507 assert_eq!(fp.mant, (1<<52) + 2); 508 assert_eq!(fp.exp, -52); 509 510 // Below halfway 511 let mut fp = ExtendedFloat80 { mant: 0x80000000000003FF, exp: -63 }; 512 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 513 assert_eq!(fp.mant, 1<<52); 514 assert_eq!(fp.exp, -52); 515 516 let mut fp = ExtendedFloat80 { mant: 0x8000000000000BFF, exp: -63 }; 517 round_to_float::<f64, _, _>(&mut fp, round_nearest_tie_even); 518 assert_eq!(fp.mant, (1<<52) + 1); 519 assert_eq!(fp.exp, -52); 520 } 521 522 #[test] avoid_overflow_test()523 fn avoid_overflow_test() { 524 // Avoid overflow, fails by 1 525 let mut fp = ExtendedFloat80 { mant: 0xFFFFFFFFFFFF, exp: f64::MAX_EXPONENT + 5 }; 526 avoid_overflow::<f64, _>(&mut fp); 527 assert_eq!(fp.mant, 0xFFFFFFFFFFFF); 528 assert_eq!(fp.exp, f64::MAX_EXPONENT+5); 529 530 // Avoid overflow, succeeds 531 let mut fp = ExtendedFloat80 { mant: 0xFFFFFFFFFFFF, exp: f64::MAX_EXPONENT + 4 }; 532 avoid_overflow::<f64, _>(&mut fp); 533 assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0); 534 assert_eq!(fp.exp, f64::MAX_EXPONENT-1); 535 } 536 537 #[test] round_to_native_test()538 fn round_to_native_test() { 539 // Overflow 540 let mut fp = ExtendedFloat80 { mant: 0xFFFFFFFFFFFF, exp: f64::MAX_EXPONENT + 4 }; 541 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 542 assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0); 543 assert_eq!(fp.exp, f64::MAX_EXPONENT-1); 544 545 // Need denormal 546 let mut fp = ExtendedFloat80 { mant: 1, exp: f64::DENORMAL_EXPONENT +48 }; 547 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 548 assert_eq!(fp.mant, 1<<48); 549 assert_eq!(fp.exp, f64::DENORMAL_EXPONENT); 550 551 // Halfway, round-down (b'10000000000000000000000000000000000000000000000000000100000') 552 let mut fp = ExtendedFloat80 { mant: 0x400000000000020, exp: -58 }; 553 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 554 assert_eq!(fp.mant, 1<<52); 555 assert_eq!(fp.exp, -52); 556 557 // Halfway, round-up (b'10000000000000000000000000000000000000000000000000001100000') 558 let mut fp = ExtendedFloat80 { mant: 0x400000000000060, exp: -58 }; 559 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 560 assert_eq!(fp.mant, (1<<52) + 2); 561 assert_eq!(fp.exp, -52); 562 563 // Above halfway 564 let mut fp = ExtendedFloat80 { mant: 0x400000000000021, exp: -58 }; 565 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 566 assert_eq!(fp.mant, (1<<52)+1); 567 assert_eq!(fp.exp, -52); 568 569 let mut fp = ExtendedFloat80 { mant: 0x400000000000061, exp: -58 }; 570 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 571 assert_eq!(fp.mant, (1<<52) + 2); 572 assert_eq!(fp.exp, -52); 573 574 // Below halfway 575 let mut fp = ExtendedFloat80 { mant: 0x40000000000001F, exp: -58 }; 576 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 577 assert_eq!(fp.mant, 1<<52); 578 assert_eq!(fp.exp, -52); 579 580 let mut fp = ExtendedFloat80 { mant: 0x40000000000005F, exp: -58 }; 581 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 582 assert_eq!(fp.mant, (1<<52) + 1); 583 assert_eq!(fp.exp, -52); 584 585 // Underflow 586 // Adapted from failures in strtod. 587 let mut fp = ExtendedFloat80 { exp: -1139, mant: 18446744073709550712 }; 588 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 589 assert_eq!(fp.mant, 0); 590 assert_eq!(fp.exp, 0); 591 592 let mut fp = ExtendedFloat80 { exp: -1139, mant: 18446744073709551460 }; 593 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 594 assert_eq!(fp.mant, 0); 595 assert_eq!(fp.exp, 0); 596 597 let mut fp = ExtendedFloat80 { exp: -1138, mant: 9223372036854776103 }; 598 round_to_native::<f64, _, _>(&mut fp, round_nearest_tie_even); 599 assert_eq!(fp.mant, 1); 600 assert_eq!(fp.exp, -1074); 601 } 602 } 603