Skip to content

Commit ba0b5a7

Browse files
authored
Merge 3dc39fe into b5de583
2 parents b5de583 + 3dc39fe commit ba0b5a7

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

library/std/src/Std/OpenQASM/Angle.qs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ function DoubleAsAngle(value : Double, size : Int) : Angle {
8585
value = value + tau;
8686
}
8787

88+
// Handle the edge case where modulo returns tau due to floating-point precision
89+
// we've seen this when the user rotates by f64::EPSILON / 2.0 causing the value
90+
// to be still equal to tau after the modulo operation.
91+
if value >= tau {
92+
value = 0.;
93+
}
94+
8895
Std.Diagnostics.Fact(value >= 0., "Value must be >= 0.");
8996
Std.Diagnostics.Fact(value < tau, "Value must be < tau.");
9097
Std.Diagnostics.Fact(size > 0, "Size must be > 0");

source/compiler/qsc_qasm/src/stdlib/angle.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ impl Angle {
5252
val += TAU;
5353
}
5454

55+
// Handle the edge case where modulo returns tau due to floating-point precision
56+
// we've seen this when the user rotates by f64::EPSILON / 2.0 causing the value
57+
// to be still equal to tau after the modulo operation.
58+
if val >= TAU {
59+
val = 0.;
60+
}
61+
62+
assert!(val >= 0., "Value must be >= 0.");
63+
assert!(val < TAU, "Value must be < tau.");
64+
assert!(size > 0, "Size must be > 0");
65+
5566
// If the size is > f64::MANTISSA_DIGITS, the cast to f64
5667
// on the next lines will loose precission.
5768
if size > f64::MANTISSA_DIGITS {

source/compiler/qsc_qasm/src/stdlib/angle/tests.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(clippy::unreadable_literal)]
66

77
use std::convert::TryInto;
8+
use std::f64;
89
use std::f64::consts::{PI, TAU};
910

1011
use super::Angle;
@@ -269,3 +270,12 @@ fn test_angle_cast_truncation() {
269270
assert_eq!(new_angle.value, 0b1010);
270271
assert_eq!(new_angle.size, 4);
271272
}
273+
274+
#[test]
275+
fn test_angle_off_by_less_than_epsilon_from_tau_maintains_invariants() {
276+
// testing (-f64::EPSILON / 2.0) % f64::EPSILON + f64::EPSILON equals f64::EPSILON
277+
// we need to ensure that the angle is still in the range [0, TAU)
278+
let angle = Angle::from_f64_maybe_sized(-f64::EPSILON / 2.0, None);
279+
assert_eq!(angle.value, 0);
280+
assert!(angle.size == 53);
281+
}

0 commit comments

Comments
 (0)