Skip to content

Commit f450734

Browse files
committed
Fix off-by-one error in X87DoubleExtended::from_bits
The standard floating point formats use an implicit bit in the significand. For example, for a 64-bit floating point value (a 'double'), the significand might be a 53-bit value, stored as 52 bits. The most significant bit is implicitly assumed to be 1. The X87 80-bit floating point format does not use an implicit bit. It stores a significand of 64 bits as 64 bits. The Semantics::PRECISION constant defines the size of the significand including the implicit bit. So for a 64-bit floating point value, Semantics::PRECISION would be 53 even though only 52 bits are used to store the significand. The code for the standard floating point formats has to work around this, by subtracting 1 from PRECISION to compute the correct number of bits. The code in X87DoubleExtended::from_bits incorrectly also subtracted 1 from PRECISION, even though no implicit bit is used in this format. Thus computing a size that is off-by-one from the actual size.
1 parent f3ab6f0 commit f450734

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

compiler/rustc_apfloat/src/ieee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl Semantics for X87DoubleExtendedS {
192192
let sign = bits & (1 << (Self::BITS - 1));
193193
let exponent = (bits & !sign) >> Self::PRECISION;
194194
let mut r = IeeeFloat {
195-
sig: [bits & ((1 << (Self::PRECISION - 1)) - 1)],
195+
sig: [bits & ((1 << Self::PRECISION) - 1)],
196196
// Convert the exponent from its bias representation to a signed integer.
197197
exp: (exponent as ExpInt) - Self::MAX_EXP,
198198
category: Category::Zero,

compiler/rustc_apfloat/tests/ieee.rs

+44
Original file line numberDiff line numberDiff line change
@@ -3299,3 +3299,47 @@ fn modulo() {
32993299
assert_eq!(status, Status::INVALID_OP);
33003300
}
33013301
}
3302+
3303+
#[test]
3304+
fn roundtrip() {
3305+
let f1 = Half::from_str_r("3.14159265358979323", Round::TowardZero).unwrap().value;
3306+
let bits1 = Half::to_bits(f1);
3307+
let f2 = Half::from_bits(bits1);
3308+
let bits2 = Half::to_bits(f2);
3309+
assert_eq!(bits1, bits2);
3310+
assert_eq!(f1, f2);
3311+
3312+
let f1 = Single::from_str_r("3.14159265358979323", Round::TowardZero).unwrap().value;
3313+
let bits1 = Single::to_bits(f1);
3314+
let f2 = Single::from_bits(bits1);
3315+
let bits2 = Single::to_bits(f2);
3316+
assert_eq!(bits1, bits2);
3317+
assert_eq!(f1, f2);
3318+
3319+
let f1 = Double::from_str_r("3.14159265358979323", Round::TowardZero).unwrap().value;
3320+
let bits1 = Double::to_bits(f1);
3321+
let f2 = Double::from_bits(bits1);
3322+
let bits2 = Double::to_bits(f2);
3323+
assert_eq!(bits1, bits2);
3324+
assert_eq!(f1, f2);
3325+
3326+
let f1 = Quad::from_str_r("3.14159265358979323", Round::TowardZero).unwrap().value;
3327+
let bits1 = Quad::to_bits(f1);
3328+
let f2 = Quad::from_bits(bits1);
3329+
let bits2 = Quad::to_bits(f2);
3330+
assert_eq!(bits1, bits2);
3331+
assert_eq!(f1, f2);
3332+
3333+
let f1 = X87DoubleExtended::from_str_r("3.14159265358979323", Round::TowardZero).unwrap().value;
3334+
let bits1 = X87DoubleExtended::to_bits(f1);
3335+
let f2 = X87DoubleExtended::from_bits(bits1);
3336+
let bits2 = X87DoubleExtended::to_bits(f2);
3337+
assert_eq!(bits1, bits2);
3338+
assert_eq!(f1, f2);
3339+
}
3340+
3341+
#[test]
3342+
fn from_bits() {
3343+
let f1 = X87DoubleExtended::from_bits(0x4000C90FDAA22168C235);
3344+
assert_eq!(&f1.to_string(), "3.14159265358979323851");
3345+
}

0 commit comments

Comments
 (0)