{"record":{"id":"d59e57687420f25f","repo":"nautechsystems/nautilus_trader","slug":"overflow-when-scaling-f64-to-fixed-point-u128","errorCode":null,"errorMessage":"Overflow when scaling f64 to fixed-point u128","messagePattern":"Overflow when scaling f64 to fixed-point u128","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/types/fixed.rs","lineNumber":947,"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_u128(value: f64, precision: u8) -> u128 {\n    check_fixed_precision(precision).expect_display(FAILED);\n    let pow1 = 10_u128.pow(u32::from(precision));\n    let pow2 = 10_u128.pow(u32::from(FIXED_PRECISION - precision));\n    let rounded = (value * pow1 as f64).round() as u128;\n    rounded\n        .checked_mul(pow2)\n        .expect(\"Overflow when scaling f64 to fixed-point u128\")\n}\n\n/// Converts a raw fixed-point `i64` value back to an `f64` value.\n#[must_use]\n#[expect(\n    clippy::cast_precision_loss,\n    reason = \"i64 to f64 is inherently lossy above 2^53; accepted for float interop\"\n)]\npub fn fixed_i64_to_f64(value: i64) -> f64 {\n    (value as f64) / FIXED_SCALAR\n}\n\n/// Converts a raw fixed-point `i128` value back to an `f64` value.\n#[must_use]\n#[expect(\n    clippy::cast_precision_loss,\n    reason = \"i128 to f64 is inherently lossy above 2^53; accepted for float interop\"\n)]","sourceCodeStart":929,"sourceCodeEnd":965,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/types/fixed.rs#L929-L965","documentation":"f64_to_fixed_u128 converts a non-negative float to raw fixed-point u128, scaling by 10^(FIXED_PRECISION - precision). The checked_mul panics with this message when the scaled result exceeds u128::MAX — the widest fixed-point representation available.","triggerScenarios":"Calling f64_to_fixed_u128 with values whose scaled magnitude exceeds u128::MAX (~3.4e38 at precision 0), typically only from unvalidated/huge float input or from casts of non-finite values saturating at the bound.","commonSituations":"Extreme synthetic values in tests (test_f64_to_fixed_u128_overflow_panics), data corruption producing astronomic magnitudes, or mis-scaled units (e.g. wei instead of ETH).","solutions":["Validate value is finite, non-negative, and within u128 representable range before conversion.","Fix unit scaling at the data source (divide by the unit factor) rather than widening further — u128 is the largest variant.","Reject the value and surface a domain error instead of converting."],"exampleFix":"// before\nlet raw = f64_to_fixed_u128(value, precision); // panics for huge values\n// after\nlet max = u128::MAX as f64 / 10f64.powi(FIXED_PRECISION);\nif !(value.is_finite() && (0.0..=max).contains(&value)) {\n    return Err(...);\n}\nlet raw = f64_to_fixed_u128(value, precision);","handlingStrategy":"validation","validationCode":"const MAX: f64 = u128::MAX as f64 / 10f64.powi(FIXED_PRECISION);\nassert!(value.is_finite() && (0.0..=MAX).contains(&value));\nlet raw = f64_to_fixed_u128(value, precision);","typeGuard":"fn fits_u128_fixed(value: f64) -> bool {\n    value.is_finite() && (0.0..=u128::MAX as f64 / 10f64.powi(FIXED_PRECISION)).contains(&value)\n}","tryCatchPattern":null,"preventionTips":["Fix unit scaling at the source (e.g. token wei vs whole units) — u128 is the widest available.","Sanitize all external numeric data for finiteness and magnitude.","Log and reject outliers instead of converting them."],"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-14T05:17:10.506Z"}