UNPKG

petcarescript

Version:

PetCareScript - A modern, expressive programming language designed for humans

333 lines (277 loc) 11.1 kB
/** * PetCareScript Standard Library - Math * Mathematical functions - VERSÃO COMPLETA E CORRIGIDA */ const MathLib = { // Constants PI: Math.PI, E: Math.E, LN2: Math.LN2, LN10: Math.LN10, LOG2E: Math.LOG2E, LOG10E: Math.LOG10E, SQRT1_2: Math.SQRT1_2, SQRT2: Math.SQRT2, // Basic functions abs: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.abs(x); }, max: (...args) => { if (args.length === 0) return -Infinity; for (const arg of args) { if (typeof arg !== 'number') throw new Error('All arguments must be numbers'); } return Math.max(...args); }, min: (...args) => { if (args.length === 0) return Infinity; for (const arg of args) { if (typeof arg !== 'number') throw new Error('All arguments must be numbers'); } return Math.min(...args); }, // Rounding round: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.round(x); }, ceil: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.ceil(x); }, floor: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.floor(x); }, trunc: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.trunc(x); }, // Powers and roots pow: (base, exponent) => { if (typeof base !== 'number' || typeof exponent !== 'number') { throw new Error('Both arguments must be numbers'); } return Math.pow(base, exponent); }, sqrt: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x < 0) throw new Error('Cannot calculate square root of negative number'); return Math.sqrt(x); }, cbrt: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.cbrt(x); }, exp: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.exp(x); }, // Logarithms log: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x <= 0) throw new Error('Logarithm argument must be positive'); return Math.log(x); }, log10: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x <= 0) throw new Error('Logarithm argument must be positive'); return Math.log10(x); }, log2: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x <= 0) throw new Error('Logarithm argument must be positive'); return Math.log2(x); }, // Trigonometry sin: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.sin(x); }, cos: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.cos(x); }, tan: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.tan(x); }, asin: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x < -1 || x > 1) throw new Error('Argument must be between -1 and 1'); return Math.asin(x); }, acos: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x < -1 || x > 1) throw new Error('Argument must be between -1 and 1'); return Math.acos(x); }, atan: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.atan(x); }, atan2: (y, x) => { if (typeof x !== 'number' || typeof y !== 'number') { throw new Error('Both arguments must be numbers'); } return Math.atan2(y, x); }, // Hyperbolic functions sinh: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.sinh(x); }, cosh: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.cosh(x); }, tanh: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.tanh(x); }, asinh: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); return Math.asinh(x); }, acosh: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x < 1) throw new Error('Argument must be >= 1'); return Math.acosh(x); }, atanh: (x) => { if (typeof x !== 'number') throw new Error('Argument must be a number'); if (x <= -1 || x >= 1) throw new Error('Argument must be between -1 and 1'); return Math.atanh(x); }, // Random functions random: () => Math.random(), randomBetween: (min, max) => { if (typeof min !== 'number' || typeof max !== 'number') { throw new Error('Both arguments must be numbers'); } return Math.random() * (max - min) + min; }, randomInt: (min, max) => { if (typeof min !== 'number' || typeof max !== 'number') { throw new Error('Both arguments must be numbers'); } return Math.floor(Math.random() * (max - min + 1)) + min; }, randomChoice: (array) => { if (!Array.isArray(array)) throw new Error('Argument must be an array'); if (array.length === 0) throw new Error('Array cannot be empty'); return array[Math.floor(Math.random() * array.length)]; }, // Precision functions toFixed: (number, decimals) => { if (typeof number !== 'number') throw new Error('First argument must be a number'); if (typeof decimals !== 'number') throw new Error('Second argument must be a number'); return Number(number.toFixed(decimals)); }, toPrecision: (number, precision) => { if (typeof number !== 'number') throw new Error('First argument must be a number'); if (typeof precision !== 'number') throw new Error('Second argument must be a number'); return Number(number.toPrecision(precision)); }, // Checks isNaN: (x) => isNaN(x), isFinite: (x) => isFinite(x), isInteger: (x) => Number.isInteger(x), // Conversions degreesToRadians: (degrees) => { if (typeof degrees !== 'number') throw new Error('Argument must be a number'); return degrees * (Math.PI / 180); }, radiansToDegrees: (radians) => { if (typeof radians !== 'number') throw new Error('Argument must be a number'); return radians * (180 / Math.PI); }, // Statistical functions sum: (array) => { if (!Array.isArray(array)) throw new Error('Argument must be an array'); return array.reduce((sum, val) => { if (typeof val !== 'number') throw new Error('All array elements must be numbers'); return sum + val; }, 0); }, average: (array) => { if (!Array.isArray(array)) throw new Error('Argument must be an array'); if (array.length === 0) throw new Error('Array cannot be empty'); return MathLib.sum(array) / array.length; }, median: (array) => { if (!Array.isArray(array)) throw new Error('Argument must be an array'); if (array.length === 0) throw new Error('Array cannot be empty'); const sorted = [...array].sort((a, b) => a - b); const mid = Math.floor(sorted.length / 2); return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid]; }, mode: (array) => { if (!Array.isArray(array)) throw new Error('Argument must be an array'); if (array.length === 0) throw new Error('Array cannot be empty'); const frequency = {}; let maxFreq = 0; let modes = []; for (const num of array) { frequency[num] = (frequency[num] || 0) + 1; if (frequency[num] > maxFreq) { maxFreq = frequency[num]; modes = [num]; } else if (frequency[num] === maxFreq && !modes.includes(num)) { modes.push(num); } } return modes.length === 1 ? modes[0] : modes; }, variance: (array, population = false) => { if (!Array.isArray(array)) throw new Error('Argument must be an array'); if (array.length === 0) throw new Error('Array cannot be empty'); const mean = MathLib.average(array); const squaredDiffs = array.map(val => Math.pow(val - mean, 2)); const divisor = population ? array.length : array.length - 1; return MathLib.sum(squaredDiffs) / divisor; }, standardDeviation: (array, population = false) => { return Math.sqrt(MathLib.variance(array, population)); }, // Utility functions clamp: (value, min, max) => { if (typeof value !== 'number' || typeof min !== 'number' || typeof max !== 'number') { throw new Error('All arguments must be numbers'); } return Math.max(min, Math.min(max, value)); }, lerp: (start, end, factor) => { if (typeof start !== 'number' || typeof end !== 'number' || typeof factor !== 'number') { throw new Error('All arguments must be numbers'); } return start + (end - start) * factor; }, map: (value, fromMin, fromMax, toMin, toMax) => { if (typeof value !== 'number' || typeof fromMin !== 'number' || typeof fromMax !== 'number' || typeof toMin !== 'number' || typeof toMax !== 'number') { throw new Error('All arguments must be numbers'); } const factor = (value - fromMin) / (fromMax - fromMin); return MathLib.lerp(toMin, toMax, factor); }, // Distance functions distance2D: (x1, y1, x2, y2) => { if (typeof x1 !== 'number' || typeof y1 !== 'number' || typeof x2 !== 'number' || typeof y2 !== 'number') { throw new Error('All arguments must be numbers'); } return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); }, distance3D: (x1, y1, z1, x2, y2, z2) => { if (typeof x1 !== 'number' || typeof y1 !== 'number' || typeof z1 !== 'number' || typeof x2 !== 'number' || typeof y2 !== 'number' || typeof z2 !== 'number') { throw new Error('All arguments must be numbers'); } return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)); } }; module.exports = MathLib;