UNPKG

tough-rational

Version:

Rational class using BigInt with fallback to bignumber.js

88 lines (78 loc) 2.91 kB
'use strict'; const generate = require('./generate'); const gcd = require('./gcd'); const util = require('../util'); const compat = require('../compat'); const pow = require('./pow-generator')(); const bufferToHex = require('../util/buffer-to-hex'); const isBuffer = require('../util/is-buffer'); const flow = require('../util/flow'); const parseFromBigInt = n => [n, BigInt(1)]; let parseFromCoercedBigInt; let mapToBigInt; if (compat.testForBigInt()) { parseFromCoercedBigInt = util.flow(BigInt, parseFromBigInt); mapToBigInt = util.map(BigInt); } const parseFromNumber = n => { if (n !== n) return generate.generateNaN(); if (n === Infinity) return generate.generateInfinity(); if (n === -Infinity) return generate.generateNegativeInfinity(); const remainder = n % 1; if (!remainder) return parseFromCoercedBigInt(n); return parseFromString(String(n)); }; const exponentialRe = /^([0-9]+(?:\.[0-9]+)?)e([0-9]+)/; const numberRe = /(?:[0-9]*(?:\.[0-9]*)?|0x[0-9a-zA-Z]*)/; const beginsWithHexPrefixRe = /^0x/; const parseFromString = s => { let match; if ((match = s.match(exponentialRe))) { const decimalAt = match[1].lastIndexOf('.'); const decimalPlaces = ~decimalAt ? match[1].length - decimalAt - 1 : 0; return gcd.gcdReduce([ pow(BigInt(10), BigInt(+match[2])) * BigInt(match[1].replace('.', '')), pow(BigInt(10), BigInt(decimalPlaces)), ]); } if (!s.match(numberRe)) return generateNaN(); if (s.match(beginsWithHexPrefixRe)) return parseFromHexString(s); if (util.last(s) === '.') s.replace('.', ''); const lastDecimal = s.lastIndexOf('.'); if (!~lastDecimal) return parseFromCoercedBigInt(s); const decimalPlaces = s.length - lastDecimal - 1; return gcd.gcdReduce([ BigInt(s.replace('.', '')), pow(BigInt(10), BigInt(decimalPlaces)), ]); }; const parseFromHexString = parseFromCoercedBigInt; const parseFromBuffer = flow(bufferToHex, parseFromHexString); const parseDynamic = input => isBuffer(input) ? parseFromBuffer(input) : typeof input === 'string' ? parseFromString(input) : typeof input === 'number' ? parseFromNumber(input) : typeof input === 'bigint' ? parseFromBigInt(input) : typeof input === 'boolean' ? input ? parseFromBigInt(BigInt(1)) : generate.generateZero() : typeof input === 'object' && Array.isArray(input) ? mapToBigInt(input) : typeof input === 'object' && (typeof input.numerator === 'bigint' || typeof input.numerator === 'symbol') && typeof input.denominator === 'bigint' ? input._getPrimitives() : generate.generateZero(); Object.assign(module.exports, { parseFromBigInt, parseFromCoercedBigInt, parseFromNumber, parseFromString, parseFromBuffer, parseFromHexString, parseDynamic, });