Skip to content

Commit

Permalink
Remove division by zero check for floating point (#979)
Browse files Browse the repository at this point in the history
This change removes division by zero checks for floating point values
and returns to previous behavior for Q#. Specifically:
 - 0.0 / 0.0 produces NaN
 - 1.0 / 0.0 produces inf
 - -1.0 / 0.0 produces -inf

To work with infinite values, this also reintroduces
`Microsoft.Quantum.Math.IsInfinite` as a counterpart to `IsNaN` in the
same namespace.

Fixes #870
  • Loading branch information
swernli authored Jan 8, 2024
1 parent caa3872 commit 04834e7
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 26 deletions.
6 changes: 1 addition & 5 deletions compiler/qsc_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1731,11 +1731,7 @@ fn eval_binop_div(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Resu
}
Value::Double(val) => {
let rhs = rhs_val.unwrap_double();
if rhs == 0.0 {
Err(Error::DivZero(rhs_span))
} else {
Ok(Value::Double(val / rhs))
}
Ok(Value::Double(val / rhs))
}
_ => panic!("value should support div"),
}
Expand Down
33 changes: 12 additions & 21 deletions compiler/qsc_eval/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,27 +614,18 @@ fn binop_div_double() {
}

#[test]
fn binop_div_double_zero() {
check_expr(
"",
"1.2 / 0.0",
&expect![[r#"
(
DivZero(
PackageSpan {
package: PackageId(
2,
),
span: Span {
lo: 6,
hi: 9,
},
},
),
[],
)
"#]],
);
fn binop_div_double_inf() {
check_expr("", "1.2 / 0.0", &expect!["inf"]);
}

#[test]
fn binop_div_double_neg_inf() {
check_expr("", "1.2 / -0.0", &expect!["-inf"]);
}

#[test]
fn binop_div_double_nan() {
check_expr("", "0.0 / 0.0", &expect!["NaN"]);
}

#[test]
Expand Down
33 changes: 33 additions & 0 deletions library/std/math.qs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,39 @@ namespace Microsoft.Quantum.Math {
return d != d;
}

/// # Summary
/// Returns whether a given floating-point value is either positive or
/// negative infinity.
///
/// # Input
/// ## d
/// The floating-point value to be checked.
///
/// # Ouput
/// `true` if and only if `d` is either positive or negative infinity.
///
/// # Remarks
/// `NaN` is not a number, and is thus neither a finite number nor
/// is it infinite. As such, `IsInfinite(0.0 / 0.0)` returns `false`.
/// To check if a value is `NaN`, use `IsNaN(d)`.
///
/// Note that even though this function returns `true` for both
/// positive and negative infinities, these values can still be
/// discriminated by checking `d > 0.0` and `d < 0.0`.
///
/// # Example
/// ```qsharp
/// Message($"{IsInfinite(42.0)}"); // false
/// Message($"{IsInfinite(0.0 / 0.0)}"); // false
/// Message($"{IsInfinite(-1.0 / 0.0}"); // true
/// ```
///
/// # See Also
/// - Microsoft.Quantum.Math.IsNaN
function IsInfinite(d : Double) : Bool {
return d == 1.0 / 0.0 or d == -1.0 / 0.0;
}

//
// Sign, Abs, Min, Max, etc.
//
Expand Down
20 changes: 20 additions & 0 deletions library/tests/src/test_math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,33 @@ fn check_log_of_2() {

#[test]
fn check_is_nan() {
test_expression(
"Microsoft.Quantum.Math.IsNaN(0.0 / 0.0)",
&Value::Bool(true),
);
test_expression("Microsoft.Quantum.Math.IsNaN(1.0)", &Value::Bool(false));
test_expression(
"Microsoft.Quantum.Math.IsNaN(Microsoft.Quantum.Math.ArcSin(2.0))",
&Value::Bool(true),
);
}

#[test]
fn check_is_infinite() {
test_expression(
"Microsoft.Quantum.Math.IsInfinite(1.0 / 0.0)",
&Value::Bool(true),
);
test_expression(
"Microsoft.Quantum.Math.IsInfinite(0.0 / 0.0)",
&Value::Bool(false),
);
test_expression(
"Microsoft.Quantum.Math.IsInfinite(-1.0 / 0.0)",
&Value::Bool(true),
);
}

//
// Sign, Abs, Min, Max, etc.
//
Expand Down

0 comments on commit 04834e7

Please sign in to comment.