fix From Base operation producing wrong results for fractional inputs

The fractional part loop used native `+=` and `Math.pow()` with BigNumber
objects, causing string concatenation instead of arithmetic addition.
Replace with BigNumber `.plus()` and `.pow()` methods.

Closes #2240

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Willi Ballenthin 2026-03-24 09:16:07 +01:00
parent b0fa1f8d1b
commit 7f10edcbc5
3 changed files with 69 additions and 1 deletions

View File

@ -51,9 +51,10 @@ class FromBase extends Operation {
if (number.length === 1) return result; if (number.length === 1) return result;
// Fractional part // Fractional part
const radixBN = new BigNumber(radix);
for (let i = 0; i < number[1].length; i++) { for (let i = 0; i < number[1].length; i++) {
const digit = new BigNumber(number[1][i], radix); const digit = new BigNumber(number[1][i], radix);
result += digit.div(Math.pow(radix, i+1)); result = result.plus(digit.div(radixBN.pow(i + 1)));
} }
return result; return result;

View File

@ -75,6 +75,7 @@ import "./tests/Float.mjs";
import "./tests/FileTree.mjs"; import "./tests/FileTree.mjs";
import "./tests/FletcherChecksum.mjs"; import "./tests/FletcherChecksum.mjs";
import "./tests/Fork.mjs"; import "./tests/Fork.mjs";
import "./tests/FromBase.mjs";
import "./tests/FromDecimal.mjs"; import "./tests/FromDecimal.mjs";
import "./tests/GenerateAllChecksums.mjs"; import "./tests/GenerateAllChecksums.mjs";
import "./tests/GenerateAllHashes.mjs"; import "./tests/GenerateAllHashes.mjs";

View File

@ -0,0 +1,66 @@
/**
* From Base operation tests.
*
* @author Willi Ballenthin
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "From Base: binary integer",
input: "1010",
expectedOutput: "10",
recipeConfig: [
{
op: "From Base",
args: [2],
},
],
},
{
name: "From Base: binary fraction",
input: "10.1",
expectedOutput: "2.5",
recipeConfig: [
{
op: "From Base",
args: [2],
},
],
},
{
name: "From Base: hex fraction",
input: "a.8",
expectedOutput: "10.5",
recipeConfig: [
{
op: "From Base",
args: [16],
},
],
},
{
name: "From Base: octal integer",
input: "77",
expectedOutput: "63",
recipeConfig: [
{
op: "From Base",
args: [8],
},
],
},
{
name: "From Base: octal fraction",
input: "7.4",
expectedOutput: "7.5",
recipeConfig: [
{
op: "From Base",
args: [8],
},
],
},
]);