UNPKG

bigfloat-esnext

Version:

A library for arbitrary precision floating point arithmetic.

164 lines (163 loc) 5.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.scientific = exports.string = exports.make = exports.fraction = exports.integer = exports.normalize = exports.number = exports.make_big_float = void 0; const arithmetic_js_1 = require("./arithmetic.js"); const constants_js_1 = require("./constants.js"); const predicates_js_1 = require("./predicates.js"); function make_big_float(coefficient, exponent) { if (coefficient === constants_js_1.BIGINT_ZERO) { return constants_js_1.ZERO; } const new_big_float = Object.create(null); new_big_float.coefficient = coefficient; new_big_float.exponent = exponent; return Object.freeze(new_big_float); } exports.make_big_float = make_big_float; function number(a) { if (typeof a !== "number" && typeof a !== "string") { if (typeof a === "bigint") { return Number(a); } else if (predicates_js_1.is_big_float(a)) { return a.exponent === 0 ? Number(a.coefficient) : Number(a.coefficient) * 10 ** a.exponent; } } return Number(a); } exports.number = number; function normalize(a) { let { coefficient, exponent } = a; // If the exponent is zero, it is already normal. if (exponent !== 0) { if (exponent > 0) { coefficient = coefficient * constants_js_1.BIGINT_TEN ** BigInt(exponent); exponent = 0; } else { let quotient; let remainder; // tslint:disable-next-line: no-bitwise while (exponent <= -7) { quotient = coefficient / constants_js_1.BIGINT_TEN_MILLION; remainder = coefficient % constants_js_1.BIGINT_TEN_MILLION; if (remainder !== constants_js_1.BIGINT_ZERO) { break; } coefficient = quotient; exponent += 7; } while (exponent < 0) { quotient = coefficient / constants_js_1.BIGINT_TEN; remainder = coefficient % constants_js_1.BIGINT_TEN; if (remainder !== constants_js_1.BIGINT_ZERO) { break; } coefficient = quotient; exponent += 1; } } } return make_big_float(coefficient, exponent); } exports.normalize = normalize; function integer(a) { // The integer function is like the normalize function except that it throws // away significance. It discards the digits after the decimal point. const { coefficient, exponent } = a; // If the exponent is zero, it is already an integer. if (exponent === 0) { return a; } // If the exponent is positive, // multiply the coefficient by 10 ** exponent. if (exponent > 0) { return make_big_float(coefficient * constants_js_1.BIGINT_TEN ** BigInt(exponent), 0); } // If the exponent is negative, divide the coefficient by 10 ** -exponent. // This truncates the unnecessary bits. This might be a zero result. return make_big_float(coefficient / constants_js_1.BIGINT_TEN ** BigInt(-exponent), 0); } exports.integer = integer; function fraction(a) { return arithmetic_js_1.sub(a, integer(a)); } exports.fraction = fraction; function make(a, b) { const number_pattern = /^(-?\d+)(?:\.(\d*))?(?:e(-?\d+))?$/; // . Capturing groups // . [1] int // . [2] frac // . [3] exp if (typeof a === "bigint") { return make_big_float(a, Number(b) || 0); } else if (typeof a === "string" || typeof a === "number") { a = String(a); if (Number.isSafeInteger(Number(b))) { return make(BigInt(parseInt(a, Number(b))), 0); } const parts = a.match(number_pattern); if (parts) { const frac = parts[2] || ""; return make(BigInt(parts[1] + frac), (Number(parts[3]) || 0) - frac.length); } } else if (predicates_js_1.is_big_float(a)) { return a; } return constants_js_1.ZERO; } exports.make = make; function string(a, radix) { if (predicates_js_1.is_zero(a)) { return "0"; } if (radix && predicates_js_1.is_big_float(radix)) { radix = normalize(radix); return radix && radix.exponent === 0 ? integer(a).coefficient.toString(Number(radix.coefficient)) : undefined; } a = normalize(a); let s = (predicates_js_1.is_negative(a) ? -a.coefficient : a.coefficient).toString(); if (a.exponent < 0) { let point = s.length + a.exponent; if (point <= 0) { s = "0".repeat(1 - point) + s; point = 1; } s = s.slice(0, point) + "." + s.slice(point); } else if (a.exponent > 0) { s += "0".repeat(a.exponent); } if (predicates_js_1.is_negative(a)) { s = "-" + s; } return s; } exports.string = string; function scientific(a) { if (predicates_js_1.is_zero(a)) { return "0"; } a = normalize(a); let s = String(predicates_js_1.is_negative(a) ? -a.coefficient : a.coefficient); const e = a.exponent + s.length - 1; if (s.length > 1) { s = s.slice(0, 1) + "." + s.slice(1); } if (e !== 0) { s += "e" + e; } if (predicates_js_1.is_negative(a)) { s = "-" + s; } return s; } exports.scientific = scientific;