From 04834e7246e38962bd34e896469e583357146e90 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 8 Jan 2024 11:16:11 -0800 Subject: [PATCH] Remove division by zero check for floating point (#979) 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 --- compiler/qsc_eval/src/lib.rs | 6 +----- compiler/qsc_eval/src/tests.rs | 33 ++++++++++++--------------------- library/std/math.qs | 33 +++++++++++++++++++++++++++++++++ library/tests/src/test_math.rs | 20 ++++++++++++++++++++ 4 files changed, 66 insertions(+), 26 deletions(-) diff --git a/compiler/qsc_eval/src/lib.rs b/compiler/qsc_eval/src/lib.rs index 931daa5d4a..374cbc8921 100644 --- a/compiler/qsc_eval/src/lib.rs +++ b/compiler/qsc_eval/src/lib.rs @@ -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"), } diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs index 61b9b29672..ac9e12b6a2 100644 --- a/compiler/qsc_eval/src/tests.rs +++ b/compiler/qsc_eval/src/tests.rs @@ -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] diff --git a/library/std/math.qs b/library/std/math.qs index 6e1a6ed66e..665171ac31 100644 --- a/library/std/math.qs +++ b/library/std/math.qs @@ -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. // diff --git a/library/tests/src/test_math.rs b/library/tests/src/test_math.rs index 6f04ee2c6c..f9651352e5 100644 --- a/library/tests/src/test_math.rs +++ b/library/tests/src/test_math.rs @@ -37,6 +37,10 @@ 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))", @@ -44,6 +48,22 @@ fn check_is_nan() { ); } +#[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. //