bigfloat-esnext
Version:
A library for arbitrary precision floating point arithmetic.
164 lines (163 loc) • 5.5 kB
JavaScript
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;
;