Skip to content

Commit 6973fd7

Browse files
committed
Add bit twiddling
1 parent bd68de8 commit 6973fd7

File tree

2 files changed

+19
-15
lines changed

2 files changed

+19
-15
lines changed

src/libcore/num/f32.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ impl f32 {
857857
let mut left = self.to_bits() as i32;
858858
let mut right = other.to_bits() as i32;
859859

860-
// In case of negatives, flip all the bits except the sign
860+
// In case of negatives, flip all the bits expect the sign
861861
// to achieve a similar layout as two's complement integers
862862
//
863863
// Why does this work? IEEE 754 floats consist of three fields:
@@ -872,13 +872,15 @@ impl f32 {
872872
// To easily compare the floats as signed integers, we need to
873873
// flip the exponent and mantissa bits in case of negative numbers.
874874
// We effectively convert the numbers to "two's complement" form.
875-
if left < 0 {
876-
// i32::MAX corresponds the bit pattern of "all ones except for the sign bit"
877-
left ^= i32::MAX
878-
};
879-
if right < 0 {
880-
right ^= i32::MAX
881-
};
875+
//
876+
// To do the flipping, we construct a mask and XOR against it.
877+
// We branchlessly calculate an "all-ones expect for the sign bit"
878+
// mask from negative-signed values: right shifting sign-extends
879+
// the integer, so we "fill" the mask with sign bits, and then
880+
// convert to unsigned to push one more zero bit.
881+
// On positive values, the mask is all zeros, so it's a no-op.
882+
left ^= (((left >> 31) as u32) >> 1) as i32;
883+
right ^= (((right >> 31) as u32) >> 1) as i32;
882884

883885
left.cmp(&right)
884886
}

src/libcore/num/f64.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -886,13 +886,15 @@ impl f64 {
886886
// To easily compare the floats as signed integers, we need to
887887
// flip the exponent and mantissa bits in case of negative numbers.
888888
// We effectively convert the numbers to "two's complement" form.
889-
if left < 0 {
890-
// i64::MAX corresponds the bit pattern of "all ones expect for the sign bit"
891-
left ^= i64::MAX
892-
};
893-
if right < 0 {
894-
right ^= i64::MAX
895-
};
889+
//
890+
// To do the flipping, we construct a mask and XOR against it.
891+
// We branchlessly calculate an "all-ones expect for the sign bit"
892+
// mask from negative-signed values: right shifting sign-extends
893+
// the integer, so we "fill" the mask with sign bits, and then
894+
// convert to unsigned to push one more zero bit.
895+
// On positive values, the mask is all zeros, so it's a no-op.
896+
left ^= (((left >> 63) as u64) >> 1) as i64;
897+
right ^= (((right >> 63) as u64) >> 1) as i64;
896898

897899
left.cmp(&right)
898900
}

0 commit comments

Comments
 (0)