From 803416d08de0ee559aa3ab7a286c45c700cddf1e Mon Sep 17 00:00:00 2001 From: Ad5001 Date: Tue, 10 Oct 2023 01:33:57 +0200 Subject: [PATCH] New system for integrals the same as for derivatives. --- .../ad5001/LogarithmPlotter/js/math/common.js | 63 ++++++++++++------- .../ad5001/LogarithmPlotter/js/math/latex.js | 8 ++- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/common.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/common.js index 9aabfd7..86d16e6 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/common.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/common.js @@ -44,34 +44,55 @@ const parser = new ExprEval.Parser() parser.consts = Object.assign({}, parser.consts, evalVariables) +/** + * Parses arguments for a function, returns the corresponding JS function if it exists. + * Throws either usage error otherwise. + * @param {array} args - Arguments of the function, either [ ExecutableObject ] or [ string, variable ]. + * @param {string} usage1 - Usage for executable object. + * @param {string} usage2 - Usage for string function. + * @return {callable} JS function to call.. + */ +function parseArgumentsForFunction(args, usage1, usage2) { + let f, target, variable + if(args.length == 1) { + // Parse object + f = args[0] + if(typeof f != 'object' || !f.execute) + throw EvalError(qsTranslate('usage', 'Usage: %1').arg(usage1)) + let target = f + f = (x) => target.execute(x) + } else if(args.length == 2) { + // Parse variable + [f,variable] = args + if(typeof f != 'string' || typeof variable != 'number') + throw EvalError(qsTranslate('usage', 'Usage: %1').arg(usage2)) + f = parser.parse(f).toJSFunction(variable, currentVars) + } else + throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2').arg(usage1).arg(usage2))) + return f +} + // Function definition -parser.functions.integral = function(a, b, f, variable) { +parser.functions.integral = function(a, b, ...args) { + let usage1 = qsTranslate('usage', 'integral(, , )') + let usage2 = qsTranslate('usage', 'integral(, , , )') + let f = parseArgumentsForFunction(args, usage1, usage2) + if(a == null || b == null) + throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2').arg(usage1).arg(usage2))) + // https://en.wikipedia.org/wiki/Simpson%27s_rule // Simpler, faster than tokenizing the expression - f = parser.parse(f).toJSFunction(variable, currentVars) return (b-a)/6*(f(a)+4*f((a+b)/2)+f(b)) } parser.functions.derivative = function(...args) { - let f, target, variable, x - if(args.length == 2) { - [f, x] = args - if(typeof f != 'object' || !f.execute) - throw EvalError(qsTranslate('usage', 'Usage: %1') - .arg(qsTranslate('usage', 'derivative(, )'))) - target = f - f = (x) => target.execute(x) - } else if(args.length == 3) { - [f, variable, x] = args - if(typeof f != 'string') - throw EvalError(qsTranslate('usage', 'Usage: %1') - .arg(qsTranslate('usage', 'derivative(, , )'))) - f = parser.parse(f).toJSFunction(variable, currentVars) - } else - throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2') - .arg(qsTranslate('usage', 'derivative(, , )') - .arg(qsTranslate('usage', 'derivative(, , )')))) - + let usage1 = qsTranslate('usage', 'derivative(, )') + let usage2 = qsTranslate('usage', 'derivative(, , )') + let x = args.pop() + let f = parseArgumentsForFunction(args, usage1, usage2) + if(x == null) + throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2').arg(usage1).arg(usage2))) + let derivative_precision = x/10 return (f(x+derivative_precision/2)-f(x-derivative_precision/2))/derivative_precision } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js index 4f25651..1e84912 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js @@ -71,16 +71,18 @@ function parif(elem, contents) { * @returns {string} */ function functionToLatex(f, args) { - console.log("Generating latex", f, args) switch(f) { case "derivative": if(args.length == 3) return '\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(args[1].substr(1, args[1].length-2), 'g'), 'x') + '}{dx}'; else - return '\\frac{d' + args[0] + '}{dx}'; + return '\\frac{d' + args[0] + '}{dx}(x)'; break; case "integral": - return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3].substr(1, args[3].length-2); + if(args.length == 4) + return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3].substr(1, args[3].length-2); + else + return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2] + '(t) dt'; break; case "sqrt": return '\\sqrt\\left(' + args.join(', ') + '\\right)';