{"record":{"id":"70030b9333bc12b1","repo":"databendlabs/databend","slug":"division-resulted-in-nan","errorCode":null,"errorMessage":"Division resulted in NaN","messagePattern":"Division resulted in NaN","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/base/src/base/ordered_float.rs","lineNumber":1385,"sourceCode":"    }\n}\n\nimpl<'a, T: FloatCore + Product + 'a> Product<&'a NotNan<T>> for NotNan<T> {\n    #[inline]\n    fn product<I: Iterator<Item = &'a NotNan<T>>>(iter: I) -> Self {\n        iter.cloned().product()\n    }\n}\n\n/// Divides a float directly.\n///\n/// Panics if the provided value is NaN or the computation results in NaN\nimpl<T: FloatCore> Div<T> for NotNan<T> {\n    type Output = Self;\n\n    #[inline]\n    fn div(self, other: T) -> Self {\n        NotNan::new(self.0 / other).expect(\"Division resulted in NaN\")\n    }\n}\n\n/// Calculates `%` with a float directly.\n///\n/// Panics if the provided value is NaN or the computation results in NaN\nimpl<T: FloatCore> Rem<T> for NotNan<T> {\n    type Output = Self;\n\n    #[inline]\n    fn rem(self, other: T) -> Self {\n        NotNan::new(self.0 % other).expect(\"Rem resulted in NaN\")\n    }\n}\n\nmacro_rules! impl_not_nan_binop {\n    ($imp:ident, $method:ident, $assign_imp:ident, $assign_method:ident) => {\n        impl<T: FloatCore> $imp for NotNan<T> {","sourceCodeStart":1367,"sourceCodeEnd":1403,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/common/base/src/base/ordered_float.rs#L1367-L1403","documentation":"The Div impl for NotNan<T> divides self.0 by a raw T and validates via NotNan::new, panicking with this message if the quotient is NaN. IEEE division produces NaN for 0/0 and inf/inf (and any NaN operand); ordinary x/0 gives inf, which is allowed here. The panic upholds the no-NaN invariant.","triggerScenarios":"Using `/` (std::ops::Div<T> for NotNan<T>) where both operands are zero (0.0 / 0.0), both are infinite with the same sign, or `other` is NaN.","commonSituations":"Normalizing by a count that is 0 (0/0), computing ratios of two metrics that both overflowed to inf, or dividing by parsed input that was never checked as finite/nonzero.","solutions":["Check the divisor: ensure `other.is_finite() && other != 0.0` (and numerator not inf) before dividing.","Use fallible construction `NotNan::new(a.0 / b).ok()` and handle the degenerate case explicitly.","Return a default (e.g. 0 or Option) for degenerate 0/0 ratios instead of performing the division."],"exampleFix":"// before\nlet ratio = notnan_count / total; // 0/0 panics\n// after\nlet ratio = if total != 0.0 && total.is_finite() { notnan_count / total } else { NotNan::new(0.0).unwrap() };","handlingStrategy":"validation","validationCode":"fn can_div(a: &NotNan<f64>, b: f64) -> bool {\n    b != 0.0 && b.is_finite() && !(a.0.is_infinite())\n}","typeGuard":"fn is_valid_divisor(x: f64) -> bool { x != 0.0 && x.is_finite() }","tryCatchPattern":"let ratio = std::panic::catch_unwind(|| notnan_count / total).ok();","preventionTips":["Always check divisor != 0.0 and is_finite() before dividing.","Handle the 0/0 case with an explicit default or Option return.","Keep counts/normalizers as integers until the final division."],"tags":["rust","float","nan","division","zero-division","panic"],"backgroundTag":"nan-arithmetic-panic","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}