{"record":{"id":"7d0a8ab5e8baf546","repo":"nautechsystems/nautilus_trader","slug":"overflow-when-scaling-f64-to-fixed-point-u64","errorCode":null,"errorMessage":"Overflow when scaling f64 to fixed-point u64","messagePattern":"Overflow when scaling f64 to fixed-point u64","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/types/fixed.rs","lineNumber":921,"sourceCode":"/// # Panics\n///\n/// Panics if `precision` exceeds [`FIXED_PRECISION`], or if scaling the rounded value\n/// overflows the raw integer range.\n#[must_use]\n#[expect(\n    clippy::cast_precision_loss,\n    clippy::cast_possible_truncation,\n    clippy::cast_sign_loss,\n    reason = \"f64 to fixed-point conversion is inherently lossy; callers validate range and finiteness\"\n)]\npub fn f64_to_fixed_u64(value: f64, precision: u8) -> u64 {\n    check_fixed_precision(precision).expect_display(FAILED);\n    let pow1 = 10_u64.pow(u32::from(precision));\n    let pow2 = 10_u64.pow(u32::from(FIXED_PRECISION - precision));\n    let rounded = (value * pow1 as f64).round() as u64;\n    rounded\n        .checked_mul(pow2)\n        .expect(\"Overflow when scaling f64 to fixed-point u64\")\n}\n\n/// Converts an `f64` value to a raw fixed-point `u128` representation with a specified precision.\n///\n/// Callers are expected to validate that `value` is finite and non-negative; non-finite\n/// and negative values saturate at the integer bounds during the float-to-integer cast.\n///\n/// # Panics\n///\n/// Panics if `precision` exceeds [`FIXED_PRECISION`], or if scaling the rounded value\n/// overflows the raw integer range.\n#[must_use]\n#[expect(\n    clippy::cast_precision_loss,\n    clippy::cast_possible_truncation,\n    clippy::cast_sign_loss,\n    reason = \"f64 to fixed-point conversion is inherently lossy; callers validate range and finiteness\"\n)]","sourceCodeStart":903,"sourceCodeEnd":939,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/types/fixed.rs#L903-L939","documentation":"f64_to_fixed_u64 converts a non-negative float to raw fixed-point u64, scaling the rounded value by 10^(FIXED_PRECISION - precision). The checked_mul panics with this message when the scaled value exceeds u64::MAX. Callers must ensure the value is finite and non-negative and within range.","triggerScenarios":"Calling f64_to_fixed_u64 with a value whose scaled magnitude exceeds u64::MAX (~1.8e19 at precision 0); the dedicated test test_f64_to_fixed_u64_overflow_panics exercises exactly this.","commonSituations":"Large unsigned quantities from feeds or computed values (e.g. cumulative volumes in base units), or accidental negative/infinite values cast to u64 before the multiplication overflow check.","solutions":["Pre-check that value * 10^FIXED_PRECISION fits in u64 and reject or clamp otherwise.","Use f64_to_fixed_u128 for larger magnitudes.","Route values that can be negative through the signed variant f64_to_fixed_i64 instead."],"exampleFix":"// before\nlet raw = f64_to_fixed_u64(huge_value, precision); // panics\n// after\nlet max = u64::MAX as f64 / 10f64.powi(FIXED_PRECISION);\nassert!(value.is_finite() && value >= 0.0 && value <= max);\nlet raw = f64_to_fixed_u64(value, precision);","handlingStrategy":"validation","validationCode":"const MAX: f64 = u64::MAX as f64 / 10f64.powi(FIXED_PRECISION);\nassert!(value.is_finite() && (0.0..=MAX).contains(&value));\nlet raw = f64_to_fixed_u64(value, precision);","typeGuard":"fn fits_u64_fixed(value: f64) -> bool {\n    value.is_finite() && (0.0..=u64::MAX as f64 / 10f64.powi(FIXED_PRECISION)).contains(&value)\n}","tryCatchPattern":null,"preventionTips":["Ensure negative values go to the signed (i64) conversion path, never the unsigned one.","Clamp cumulative totals before converting.","Unit-test the exact overflow threshold for your precision settings."],"tags":["rust","overflow","fixed-point","arithmetic"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}