{"record":{"id":"ce6b9d46ff3c4f24","repo":"gchq/CyberChef","slug":"fractional-values-are-not-supported-by-bcd","errorCode":null,"errorMessage":"Fractional values are not supported by BCD","messagePattern":"Fractional values are not supported by BCD","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/ToBCD.mjs","lineNumber":63,"sourceCode":"            },\n            {\n                \"name\": \"Output format\",\n                \"type\": \"option\",\n                \"value\": FORMAT\n            }\n        ];\n    }\n\n    /**\n     * @param {BigNumber} input\n     * @param {Object[]} args\n     * @returns {string}\n     */\n    run(input, args) {\n        if (input.isNaN())\n            throw new OperationError(\"Invalid input\");\n        if (!input.integerValue(BigNumber.ROUND_DOWN).isEqualTo(input))\n            throw new OperationError(\"Fractional values are not supported by BCD\");\n\n        const encoding = ENCODING_LOOKUP[args[0]],\n            packed = args[1],\n            signed = args[2],\n            outputFormat = args[3];\n\n        // Split input number up into separate digits\n        const digits = input.toFixed().split(\"\");\n\n        if (digits[0] === \"-\" || digits[0] === \"+\") {\n            digits.shift();\n        }\n\n        let nibbles = [];\n\n        digits.forEach(d => {\n            const n = parseInt(d, 10);\n            nibbles.push(encoding[n]);","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/ToBCD.mjs#L45-L81","documentation":"To BCD only encodes integer values; it rejects any number whose integer-truncated value differs from itself (i.e. numbers with a non-zero fractional part). BCD stores whole decimal digits and has no representation for a fractional component in this implementation.","triggerScenarios":"Passing a fractional number such as 12.5 or -3.14 to To BCD. The guard compares the ROUND_DOWN integer to the original and throws when they are unequal.","commonSituations":"Forggetting to truncate/round a measurement or currency value; receiving floats from upstream arithmetic.","solutions":["Round or truncate the input to a whole number before To BCD.","Multiply and round if you need to preserve fixed-point scale, then document the scale separately.","Filter out fractional inputs upstream."],"exampleFix":"// before: input = 12.5            -> fractional, throws\n// after:  input = Math.round(12.5)  // 13  -> integer, BCD encodes 1,3","handlingStrategy":"validation","validationCode":"if (!input.integerValue(BigNumber.ROUND_DOWN).isEqualTo(input)) {\n  throw new Error(\"To BCD requires an integer\");\n}","typeGuard":"const isIntegerBN = v => v.integerValue(BigNumber.ROUND_DOWN).isEqualTo(v);","tryCatchPattern":"try { toBcd(input, ...args); }\ncatch (e) { if (/Fractional/.test(e.message)) { input = input.integerValue(BigNumber.ROUND_HALF_UP); } else throw e; }","preventionTips":["Round or truncate floats to integers before To BCD.","Apply fixed-point scaling upstream and track the scale separately.","Validate integer-ness at the form layer."],"tags":["bcd","number","integer","validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}