UNPKG

@0xtorch/big-decimal

Version:

An arbitrary precision Decimal type for TypeScript that extends BigInt.

78 lines 3.02 kB
export const createBigDecimal = (value, decimals) => { if (typeof value === 'string') { return createBigDecimalFromString(value, decimals); } if (typeof value === 'number') { return createBigDecimalFromString(value.toString(), decimals); } return createBigDecimalFromBigint(value, decimals); }; const createBigDecimalFromString = (value, decimals) => { // e で分割 const splitedValue = value.replaceAll(' ', '').split(/[eE]/); const baseValue = splitedValue[0]; const exponent = splitedValue[1]; // マイナスかどうか const isNegative = baseValue.startsWith('-'); const absText = isNegative ? baseValue.slice(1) : baseValue; // '+' ',' '_' を除外する const numberText = absText .replaceAll('+', '') .replaceAll(',', '') .replaceAll('_', ''); // . で文字列分割 // それぞれの block が数字のみで構成されていなかったらエラー const [intText, decimalText] = numberText.split('.'); const numberRegExp = /^\d+$/; if (!numberRegExp.test(intText) || (decimalText !== undefined && decimalText.length > 0 && !numberRegExp.test(decimalText))) { throw new Error(`Invalid decimal format value: ${baseValue}`); } // decimal 末尾の 0 は削除 (正規表現で良い感じに) const formattedDecimalText = decimalText !== undefined && decimalText.length > 0 ? decimalText.replace(/0+$/, '') : ''; const formattedDecimals = formattedDecimalText.length; // decimals の末尾を調整 const adjustedDecimalText = adjustDecimalText(decimals, formattedDecimalText, formattedDecimals); const valueBn = BigInt(`${isNegative ? '-' : ''}${intText}${adjustedDecimalText}`); const baseDecimals = decimals === undefined ? formattedDecimals : decimals; // 指数がない場合はそのまま返す if (exponent === undefined) { return { value: valueBn, decimals: baseDecimals, }; } // 指数がある場合は指数を考慮して返す const exponentNumber = Number(exponent); const decimalsWithExponent = baseDecimals - exponentNumber; return decimalsWithExponent < 0 ? { value: valueBn * 10n ** BigInt(-decimalsWithExponent), decimals: 0, } : { value: valueBn, decimals: decimalsWithExponent, }; }; const adjustDecimalText = (decimals, formattedDecimalText, formattedDecimals) => { if (decimals === undefined) { return formattedDecimalText; } if (decimals > formattedDecimals) { return formattedDecimalText.padEnd(decimals, '0'); } if (decimals < formattedDecimals) { return formattedDecimalText.slice(0, decimals); } return formattedDecimalText; }; const createBigDecimalFromBigint = (value, decimals) => ({ value, decimals: decimals ?? 0, }); //# sourceMappingURL=createBigDecimal.js.map