UNPKG

bigfloat.js

Version:

A library for arbitrary precision floating point arithmetic.

200 lines (199 loc) 7.73 kB
"use strict"; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; exports.__esModule = true; exports.evaluate = void 0; var arithmetic_js_1 = require("./arithmetic.js"); var constants_js_1 = require("./constants.js"); var constructors_js_1 = require("./constructors.js"); var predicates_js_1 = require("./predicates.js"); var relational_js_1 = require("./relational.js"); function evaluate(source, precision) { if (precision === void 0) { precision = constants_js_1.PRECISION; } if (typeof source !== "string") { throw Error("The first parameter was expected to be a string."); } // This function relies on an algorithm that fully parenthesizes the expression function parenthesize(expr) { return ("((((" + expr .replace(/\(/g, "((((") .replace(/\)/g, "))))") .replace(/(^|[^!])===?/g, ")))==(((") .replace(/<=/g, ")))<=(((") .replace(/>=/g, ")))>=(((") .replace(/<(?!=)/g, ")))<(((") .replace(/>(?!=)/g, ")))>(((") .replace(/!==?/g, ")))!=(((") .replace(/(^|[^e])\+/g, "))+((") .replace(/(^|[^e])-(?!\d)/g, "))-((") .replace(/\^|\*\*/g, "**") .replace(/(^|[^*])\*(?!\*)/g, ")*(") .replace(/\//g, ")/(") .replace(/%/g, ")%(") .replace(/ /g, "") + "))))"); } var expression = parenthesize(source); var rx_tokens = /(-?\d+(?:\.\d+)?(?:e(-?|\+?)\d+)?)|(\(|\))|(\+|-|\/|\*\*|==|!=|<=?|>=?|\*|\^|%)/g; // Capture groups // [1] Number // [2] Paren // [3] Operator // Tokenize the expression var tokens = (expression.match(rx_tokens) || []).map(function (element) { var parens = ["(", ")"]; var operators = [ "+", "-", "*", "**", "/", "%", "==", "!=", "<", ">", "<=", ">=" ]; if (element === "%") { throw Error("The modulo operator is not supported yet."); } if (parens.includes(element)) { return { type: "paren", value: element }; } else if (operators.includes(element)) { return { type: "operator", value: element }; } else if (predicates_js_1.is_number(element)) { return { type: "number", value: constructors_js_1.normalize(constructors_js_1.make(element.replace("+", ""))) }; } throw Error("Unexpected token \"" + element + "\""); }); var n = 0; tokens.forEach(function (element, index) { if (element.value === "**") { if (tokens[index + 2].value === "**") { tokens.splice(index + 1, 0, { value: "(", type: "paren" }); n += 1; } else { while (n) { n -= 1; tokens.splice(index + 3, 0, { value: ")", type: "paren" }); } } } }); // Recursively resolve the parentheses function resolve(arr) { // Remove parens when there's only one value if (arr.length <= 3) { return [arr[1]]; } var last_left_paren; var i = 0; var _loop_1 = function () { if (typeof last_left_paren === "number") { var value = arr[i].value; if (value === "(") { last_left_paren = i; } if (value === ")") { var start = arr.slice(0, last_left_paren); var term = arr.splice(last_left_paren, i - last_left_paren + 1); var end = arr.slice(last_left_paren, arr.length); return { value: resolve(__spreadArrays(start, resolve(term), end)) }; } if (arr[i].type === "operator" && arr[i + 1].type !== "paren") { var start = arr.slice(0, arr[i + 2].type === "operator" || arr[i + 2].type === "paren" ? last_left_paren + 1 : last_left_paren); var ops = arr.splice(i - 1, 3); var end = arr.slice(arr[i - 1].type === "operator" || (arr[i + 1] || {}).type === "paren" || i >= arr.length ? i - 1 : i, arr.length); var a_1 = ops[0].value; var b_1 = ops[2].value; var operator = ops[1].value; var bigfloat_return = { "+": function () { return arithmetic_js_1.add(a_1, b_1); }, "-": function () { return arithmetic_js_1.sub(a_1, b_1); }, "*": function () { return arithmetic_js_1.mul(a_1, b_1); }, "/": function () { return predicates_js_1.is_zero(b_1) ? constants_js_1.ZERO : arithmetic_js_1.div(a_1, b_1, precision); }, "**": function () { return arithmetic_js_1.exponentiation(a_1, b_1); } }[operator]; var boolean_return = { "==": function () { return relational_js_1.eq(a_1, b_1); }, "!=": function () { return !relational_js_1.eq(a_1, b_1); }, "<": function () { return relational_js_1.lt(a_1, b_1); }, ">": function () { return relational_js_1.gt(a_1, b_1); }, "<=": function () { return relational_js_1.lt(a_1, b_1) || relational_js_1.eq(a_1, b_1); }, ">=": function () { return relational_js_1.gt(a_1, b_1) || relational_js_1.eq(a_1, b_1); } }[operator]; var res = bigfloat_return ? { type: "number", value: bigfloat_return() } : { type: "boolean", value: boolean_return() }; return { value: resolve(__spreadArrays(start, [res], end)) }; } } i += 1; }; while (i <= arr.length) { var state_1 = _loop_1(); if (typeof state_1 === "object") return state_1.value; } } var result = resolve(tokens)[0]; if (result.type === "number") { return constructors_js_1.string(result.value); } return result.value; } exports.evaluate = evaluate;