diff --git "a/index-2.js" "b/index-2.js" new file mode 100644--- /dev/null +++ "b/index-2.js" @@ -0,0 +1,3064 @@ +// nekomaths/index.js + +/** + * Nekomaths - Un package de fonctions mathématiques simples et utiles. + * Développé par nekoclem. + */ + +/** + * Additionne deux nombres. + * @param {number} a - Le premier nombre. + * @param {number} b - Le deuxième nombre. + * @returns {number} La somme des deux nombres. + * @throws {Error} Si les arguments ne sont pas des nombres. + */ +function nekadd(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('nekadd: Les arguments doivent être des nombres.'); + } + return a + b; +} + +/** + * Soustrait le deuxième nombre du premier. + * @param {number} a - Le nombre duquel soustraire. + * @param {number} b - Le nombre à soustraire. + * @returns {number} Le résultat de la soustraction. + * @throws {Error} Si les arguments ne sont pas des nombres. + */ +function neksub(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('neksub: Les arguments doivent être des nombres.'); + } + return a - b; +} + +/** + * Multiplie deux nombres. + * @param {number} a - Le premier nombre. + * @param {number} b - Le deuxième nombre. + * @returns {number} Le produit des deux nombres. + * @throws {Error} Si les arguments ne sont pas des nombres. + */ +function nekmult(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('nekmult: Les arguments doivent être des nombres.'); + } + return a * b; +} + +/** + * Divise le premier nombre par le deuxième. + * @param {number} a - Le nombre à diviser. + * @param {number} b - Le diviseur. + * @returns {number} Le résultat de la division. + * @throws {Error} Si les arguments ne sont pas des nombres ou si le diviseur est zéro. + */ +function nekdiv(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('nekdiv: Les arguments doivent être des nombres.'); + } + if (b === 0) { + throw new Error('nekdiv: Division par zéro impossible.'); + } + return a / b; +} + +/** + * Vérifie si un nombre est pair ou impair et retourne une chaîne de caractères en français. + * @param {number} number - Le nombre à vérifier. + * @returns {string} Une chaîne de caractères indiquant si le nombre est pair ou impair. + * @throws {Error} Si l'argument n'est pas un nombre. + */ +function nekIsPairOuImpair(number) { + if (typeof number !== 'number') { + throw new Error('nekIsPairOuImpair: L\'argument doit être un nombre.'); + } + // Gérer les nombres décimaux qui pourraient avoir un modulo non entier + if (!Number.isInteger(number)) { + return `Le nombre ${number} n'est pas un entier. Il n'est ni pair ni impair.`; + } + if (number % 2 === 0) { + return `Le nombre ${number} est pair.`; + } else { + return `Le nombre ${number} est impair.`; + } +} + +/** + * Génère un nombre entier aléatoire entre deux bornes (min et max incluses). + * @param {number} min - La borne inférieure (incluse). + * @param {number} max - La borne supérieure (incluse). + * @returns {number} Un nombre entier aléatoire. + * @throws {Error} Si les arguments ne sont pas des nombres ou si min est supérieur à max. + */ +function nekorandom(min, max) { + if (typeof min !== 'number' || typeof max !== 'number') { + throw new Error('nekorandom: Les arguments min et max doivent être des nombres.'); + } + if (min > max) { + throw new Error('nekorandom: La valeur min ne peut pas être supérieure à max.'); + } + + const ceilMin = Math.ceil(min); + const floorMax = Math.floor(max); + + return Math.floor(Math.random() * (floorMax - ceilMin + 1)) + ceilMin; +} + +// --- NOUVELLES FONCTIONS AJOUTÉES --- + +/** + * Retourne le n-ième nombre de la séquence de Fibonacci. + * @param {number} n - L'index du nombre de Fibonacci à retourner (n >= 0). + * @returns {number} Le n-ième nombre de Fibonacci. + * @throws {Error} Si l'argument n'est pas un entier non négatif. + */ +function nekofibona(n) { + if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) { + throw new Error('nekofibona: L\'argument doit être un entier non négatif.'); + } + if (n === 0) return 0; + if (n === 1) return 1; + + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + let temp = a + b; + a = b; + b = temp; + } + return b; +} + +/** + * Vérifie si un nombre entier est premier. + * @param {number} number - Le nombre à vérifier. + * @returns {boolean} True si le nombre est premier, false sinon. + * @throws {Error} Si l'argument n'est pas un entier. + */ +function nekpremier(number) { + if (typeof number !== 'number' || !Number.isInteger(number)) { + throw new Error('nekpremier: L\'argument doit être un entier.'); + } + if (number <= 1) return false; + if (number <= 3) return true; // 2 et 3 sont premiers + if (number % 2 === 0 || number % 3 === 0) return false; // Optimisation pour les multiples de 2 et 3 + + // Vérifie les diviseurs à partir de 5, en sautant les multiples de 2 et 3 + for (let i = 5; i * i <= number; i = i + 6) { + if (number % i === 0 || number % (i + 2) === 0) + return false; + } + return true; +} + +/** + * Fournit des constantes mathématiques liées à Pi. + */ +const nekopi = { + /** + * La valeur de Pi (Math.PI). + * @type {number} + */ + valeur: Math.PI, + + /** + * Calcule la circonférence d'un cercle. + * @param {number} rayon - Le rayon du cercle. + * @returns {number} La circonférence. + * @throws {Error} Si l'argument n'est pas un nombre positif. + */ + circonference: function(rayon) { + if (typeof rayon !== 'number' || rayon < 0) { + throw new Error('nekopi.circonference: Le rayon doit être un nombre positif.'); + } + return 2 * Math.PI * rayon; + }, + + /** + * Calcule l'aire d'un cercle. + * @param {number} rayon - Le rayon du cercle. + * @returns {number} L'aire. + * @throws {Error} Si l'argument n'est pas un nombre positif. + */ + aireCercle: function(rayon) { + if (typeof rayon !== 'number' || rayon < 0) { + throw new Error('nekopi.aireCercle: Le rayon doit être un nombre positif.'); + } + return Math.PI * rayon * rayon; + }, + + /** + * Convertit des degrés en radians. + * @param {number} degres - La valeur en degrés. + * @returns {number} La valeur en radians. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + degresEnRadians: function(degres) { + if (typeof degres !== 'number') { + throw new Error('nekopi.degresEnRadians: L\'argument doit être un nombre.'); + } + return degres * (Math.PI / 180); + }, + + /** + * Convertit des radians en degrés. + * @param {number} radians - La valeur en radians. + * @returns {number} La valeur en degrés. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + radiansEnDegres: function(radians) { + if (typeof radians !== 'number') { + throw new Error('nekopi.radiansEnDegres: L\'argument doit être un nombre.'); + } + return radians * (180 / Math.PI); + } +}; + +/** + * Calcule la racine carrée d'un nombre. + * @param {number} number - Le nombre. + * @returns {number} La racine carrée du nombre. + * @throws {Error} Si l'argument n'est pas un nombre non négatif. + */ +function nekracine(number) { + if (typeof number !== 'number' || number < 0) { + throw new Error('nekracine: L\'argument doit être un nombre non négatif.'); + } + return Math.sqrt(number); +} + +/** + * Renvoie le double d'un nombre. + * @param {number} number - Le nombre à doubler. + * @returns {number} Le double du nombre. + * @throws {Error} Si l'argument n'est pas un nombre. + */ +function nekodouble(number) { + if (typeof number !== 'number') { + throw new Error('nekodouble: L\'argument doit être un nombre.'); + } + return number * 2; +} + +/** + * Renvoie la moitié d'un nombre. + * @param {number} number - Le nombre à diviser par deux. + * @returns {number} La moitié du nombre. + * @throws {Error} Si l'argument n'est pas un nombre. + */ +function nekomoitie(number) { + if (typeof number !== 'number') { + throw new Error('nekomoitie: L\'argument doit être un nombre.'); + } + return number / 2; +} + +/** + * Fonctions pour les calculs avec des degrés (angles). + */ +const nekdegres = { + /** + * Convertit des radians en degrés. + * (Dupliqué de nekopi pour un accès plus direct si l'utilisateur cherche juste les degrés) + * @param {number} radians - La valeur en radians. + * @returns {number} La valeur en degrés. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + enDegres: function(radians) { + if (typeof radians !== 'number') { + throw new Error('nekdegres.enDegres: L\'argument doit être un nombre.'); + } + return radians * (180 / Math.PI); + }, + + /** + * Convertit des degrés en radians. + * (Dupliqué de nekopi pour un accès plus direct si l'utilisateur cherche juste les degrés) + * @param {number} degres - La valeur en degrés. + * @returns {number} La valeur en radians. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + enRadians: function(degres) { + if (typeof degres !== 'number') { + throw new Error('nekdegres.enRadians: L\'argument doit être un nombre.'); + } + return degres * (Math.PI / 180); + }, + + /** + * Calcule le sinus d'un angle en degrés. + * @param {number} degres - L'angle en degrés. + * @returns {number} Le sinus de l'angle. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + sinus: function(degres) { + if (typeof degres !== 'number') { + throw new Error('nekdegres.sinus: L\'argument doit être un nombre.'); + } + return Math.sin(this.enRadians(degres)); + }, + + /** + * Calcule le cosinus d'un angle en degrés. + * @param {number} degres - L'angle en degrés. + * @returns {number} Le cosinus de l'angle. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + cosinus: function(degres) { + if (typeof degres !== 'number') { + throw new Error('nekdegres.cosinus: L\'argument doit être un nombre.'); + } + return Math.cos(this.enRadians(degres)); + }, + + /** + * Calcule la tangente d'un angle en degrés. + * @param {number} degres - L'angle en degrés. + * @returns {number} La tangente de l'angle. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + tangente: function(degres) { + if (typeof degres !== 'number') { + throw new Error('nekdegres.tangente: L\'argument doit être un nombre.'); + } + return Math.tan(this.enRadians(degres)); + }, + + // Vous pouvez ajouter d'autres fonctions trigonométriques inverses ou spécifiques aux triangles ici +}; + + +/** + * Retourne les facteurs premiers d'un nombre. + * @param {number} number - Le nombre à factoriser. + * @returns {Array} Un tableau contenant les facteurs premiers du nombre. + * @throws {Error} Si l'argument n'est pas un entier positif. + */ +function nekFacteurs(number) { + if (typeof number !== 'number' || !Number.isInteger(number) || number <= 1) { + throw new Error('nekFacteurs: L\'argument doit être un entier positif supérieur à 1.'); + } + const facteurs = []; + let diviseur = 2; + + while (number > 1) { + while (number % diviseur === 0) { + facteurs.push(diviseur); + number /= diviseur; + } + diviseur++; + } + return facteurs; +} + +/** + * Calcule la puissance d'un nombre. + * @param {number} base - La base. + * @param {number} exposant - L'exposant. + * @returns {number} La valeur de base élevée à exposant. + * @throws {Error} Si les arguments ne sont pas des nombres. + */ +function nekopuissance(base, exposant) { + if (typeof base !== 'number' || typeof exposant !== 'number') { + throw new Error('nekopuissance: Les arguments doivent être des nombres.'); + } + return Math.pow(base, exposant); +} + +/** + * Calcule la médiane d'un tableau de nombres. + * @param {Array} arr - Le tableau de nombres. + * @returns {number} La médiane du tableau. + * @throws {Error} Si l'argument n'est pas un tableau de nombres. + */ +function nekmed(arr) { + if (!Array.isArray(arr) || arr.some(num => typeof num !== 'number')) { + throw new Error('nekmed: L\'argument doit être un tableau de nombres.'); + } + if (arr.length === 0) { + throw new Error('nekmed: Le tableau ne peut pas être vide.'); + } + const sorted = [...arr].sort((a, b) => a - b); + const mid = Math.floor(sorted.length / 2); + return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2; +} + +/** + * Calcule la moyenne d'un tableau de nombres. + * @param {Array} arr - Le tableau de nombres. + * @returns {number} La moyenne du tableau. + * @throws {Error} Si l'argument n'est pas un tableau de nombres. + */ +function nekmoy(arr) { + if (!Array.isArray(arr) || arr.some(num => typeof num !== 'number')) { + throw new Error('nekmoy: L\'argument doit être un tableau de nombres.'); + } + if (arr.length === 0) { + throw new Error('nekmoy: Le tableau ne peut pas être vide.'); + } + return arr.reduce((sum, num) => sum + num, 0) / arr.length; +} + +/** + * Fonctions de conversion entre mètres et kilomètres. + */ +const neky = { + /** + * Convertit des mètres en kilomètres. + * @param {number} meters - La valeur en mètres. + * @returns {number} La valeur convertie en kilomètres. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + metersToKilometers: function(meters) { + if (typeof meters !== 'number') { + throw new Error('neky.metersToKilometers: L\'argument doit être un nombre.'); + } + return meters / 1000; + }, + + /** + * Convertit des kilomètres en mètres. + * @param {number} kilometers - La valeur en kilomètres. + * @returns {number} La valeur convertie en mètres. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + kilometersToMeters: function(kilometers) { + if (typeof kilometers !== 'number') { + throw new Error('neky.kilometersToMeters: L\'argument doit être un nombre.'); + } + return kilometers * 1000; + } +}; + +/** + * Fonctions de conversion d'unités personnalisables. + */ +const neklet = { + /** + * Convertit des kilos en tonnes. + * @param {number} kilos - La valeur en kilos. + * @returns {number} La valeur convertie en tonnes. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + kilosToTonnes: function(kilos) { + if (typeof kilos !== 'number') { + throw new Error('neklet.kilosToTonnes: L\'argument doit être un nombre.'); + } + return kilos / 1000; + }, + + /** + * Convertit des tonnes en kilos. + * @param {number} tonnes - La valeur en tonnes. + * @returns {number} La valeur convertie en kilos. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + tonnesToKilos: function(tonnes) { + if (typeof tonnes !== 'number') { + throw new Error('neklet.tonnesToKilos: L\'argument doit être un nombre.'); + } + return tonnes * 1000; + }, + + /** + * Convertit des grammes en kilogrammes. + * @param {number} grams - La valeur en grammes. + * @returns {number} La valeur convertie en kilogrammes. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + gramsToKilograms: function(grams) { + if (typeof grams !== 'number') { + throw new Error('neklet.gramsToKilograms: L\'argument doit être un nombre.'); + } + return grams / 1000; + }, + + /** + * Convertit des kilogrammes en grammes. + * @param {number} kilograms - La valeur en kilogrammes. + * @returns {number} La valeur convertie en grammes. + * @throws {Error} Si l'argument n'est pas un nombre. + */ + kilogramsToGrams: function(kilograms) { + if (typeof kilograms !== 'number') { + throw new Error('neklet.kilogramsToGrams: L\'argument doit être un nombre.'); + } + return kilograms * 1000; + }, + + /** + * Conversion personnalisée avec facteur. + * @param {number} value - La valeur à convertir. + * @param {number} factor - Le facteur de conversion. + * @returns {number} La valeur convertie. + * @throws {Error} Si les arguments ne sont pas des nombres. + */ + customConversion: function(value, factor) { + if (typeof value !== 'number' || typeof factor !== 'number') { + throw new Error('neklet.customConversion: Les arguments doivent être des nombres.'); + } + return value * factor; + } +}; + +/** + * Calcule le pourcentage d'un nombre. + * @param {number} total - Le nombre total. + * @param {number} pourcentage - Le pourcentage à calculer. + * @returns {number} La valeur du pourcentage. + * @throws {Error} Si les arguments ne sont pas des nombres. + */ +function nekpourcentage(total, pourcentage) { + if (typeof total !== 'number' || typeof pourcentage !== 'number') { + throw new Error('nekpourcentage: Les arguments doivent être des nombres.'); + } + return (total * pourcentage) / 100; +} + +/** + * Fonctions en rapport avec le théorème de Pythagore. + */ +const nektalor = { + /** + * Calcule l'hypoténuse d'un triangle rectangle. + * @param {number} a - Premier côté adjacent. + * @param {number} b - Deuxième côté adjacent. + * @returns {number} La longueur de l'hypoténuse. + * @throws {Error} Si les arguments ne sont pas des nombres positifs. + */ + hypotenuse: function(a, b) { + if (typeof a !== 'number' || typeof b !== 'number' || a <= 0 || b <= 0) { + throw new Error('nektalor.hypotenuse: Les arguments doivent être des nombres positifs.'); + } + return Math.sqrt(a * a + b * b); + }, + + /** + * Calcule un côté adjacent connaissant l'hypoténuse et l'autre côté. + * @param {number} hypotenuse - L'hypoténuse. + * @param {number} cote - Un côté adjacent. + * @returns {number} La longueur de l'autre côté adjacent. + * @throws {Error} Si les arguments ne sont pas des nombres positifs ou si hypoténuse <= côté. + */ + coteAdjacent: function(hypotenuse, cote) { + if (typeof hypotenuse !== 'number' || typeof cote !== 'number' || hypotenuse <= 0 || cote <= 0) { + throw new Error('nektalor.coteAdjacent: Les arguments doivent être des nombres positifs.'); + } + if (hypotenuse <= cote) { + throw new Error('nektalor.coteAdjacent: L\'hypoténuse doit être plus grande que le côté.'); + } + return Math.sqrt(hypotenuse * hypotenuse - cote * cote); + } +}; + +/** + * Fonctions pour le théorème de Thalès. + */ +const nektales = { + /** + * Calcule le quatrième terme d'une proportion de Thalès (a/b = c/x). + * @param {number} a - Premier terme. + * @param {number} b - Deuxième terme. + * @param {number} c - Troisième terme. + * @returns {number} Le quatrième terme (x). + * @throws {Error} Si les arguments ne sont pas des nombres ou si b est zéro. + */ + proportionnalite: function(a, b, c) { + if (typeof a !== 'number' || typeof b !== 'number' || typeof c !== 'number') { + throw new Error('nektales.proportionnalite: Les arguments doivent être des nombres.'); + } + if (b === 0) { + throw new Error('nektales.proportionnalite: Le deuxième terme ne peut pas être zéro.'); + } + return (b * c) / a; + }, + + /** + * Vérifie si quatre nombres forment une proportion de Thalès. + * @param {number} a - Premier terme. + * @param {number} b - Deuxième terme. + * @param {number} c - Troisième terme. + * @param {number} d - Quatrième terme. + * @returns {boolean} True si a/b = c/d, false sinon. + * @throws {Error} Si les arguments ne sont pas des nombres ou si b ou d sont zéro. + */ + verifierProportionnalite: function(a, b, c, d) { + if (typeof a !== 'number' || typeof b !== 'number' || typeof c !== 'number' || typeof d !== 'number') { + throw new Error('nektales.verifierProportionnalite: Les arguments doivent être des nombres.'); + } + if (b === 0 || d === 0) { + throw new Error('nektales.verifierProportionnalite: Les dénominateurs ne peuvent pas être zéro.'); + } + return Math.abs((a / b) - (c / d)) < 1e-10; // Tolérance pour les erreurs de flottant + } +}; + +/** + * Fonctions pour calculer des probabilités. + */ +const nekproba = { + /** + * Calcule la probabilité d'un événement (cas favorables / cas possibles). + * @param {number} casFavorables - Nombre de cas favorables. + * @param {number} casPossibles - Nombre total de cas possibles. + * @returns {number} La probabilité (entre 0 et 1). + * @throws {Error} Si les arguments ne sont pas des entiers positifs ou si cas favorables > cas possibles. + */ + probabiliteSimple: function(casFavorables, casPossibles) { + if (typeof casFavorables !== 'number' || typeof casPossibles !== 'number' || + !Number.isInteger(casFavorables) || !Number.isInteger(casPossibles) || + casFavorables < 0 || casPossibles <= 0) { + throw new Error('nekproba.probabiliteSimple: Les arguments doivent être des entiers positifs.'); + } + if (casFavorables > casPossibles) { + throw new Error('nekproba.probabiliteSimple: Le nombre de cas favorables ne peut pas dépasser le nombre de cas possibles.'); + } + return casFavorables / casPossibles; + }, + + /** + * Calcule la probabilité inverse (1 - p). + * @param {number} probabilite - La probabilité initiale (entre 0 et 1). + * @returns {number} La probabilité inverse. + * @throws {Error} Si l'argument n'est pas un nombre entre 0 et 1. + */ + probabiliteInverse: function(probabilite) { + if (typeof probabilite !== 'number' || probabilite < 0 || probabilite > 1) { + throw new Error('nekproba.probabiliteInverse: L\'argument doit être un nombre entre 0 et 1.'); + } + return 1 - probabilite; + }, + + /** + * Calcule la probabilité de l'union de deux événements (P(A ∪ B) = P(A) + P(B) - P(A ∩ B)). + * @param {number} probA - Probabilité de l'événement A. + * @param {number} probB - Probabilité de l'événement B. + * @param {number} probIntersection - Probabilité de l'intersection A ∩ B. + * @returns {number} La probabilité de A OU B. + * @throws {Error} Si les arguments ne sont pas des nombres entre 0 et 1. + */ + probabiliteUnion: function(probA, probB, probIntersection = 0) { + if (typeof probA !== 'number' || typeof probB !== 'number' || typeof probIntersection !== 'number' || + probA < 0 || probA > 1 || probB < 0 || probB > 1 || probIntersection < 0 || probIntersection > 1) { + throw new Error('nekproba.probabiliteUnion: Les arguments doivent être des nombres entre 0 et 1.'); + } + return probA + probB - probIntersection; + } +}; + +/** + * Fonction créative pour les messages personnalisés. + */ +const nekbel = { + /** + * Renvoie un message personnalisé avec formatage. + * @param {string} message - Le message à afficher. + * @param {string} style - Le style du message ('info', 'success', 'warning', 'error'). + * @returns {string} Le message formaté. + * @throws {Error} Si les arguments ne sont pas des chaînes valides. + */ + message: function(message, style = 'info') { + if (typeof message !== 'string') { + throw new Error('nekbel.message: Le message doit être une chaîne de caractères.'); + } + const styles = { + info: '💡 [INFO]', + success: '✅ [SUCCÈS]', + warning: '⚠️ [ATTENTION]', + error: '❌ [ERREUR]' + }; + const prefix = styles[style] || styles.info; + return `${prefix} ${message}`; + }, + + /** + * Exécute une fonction personnalisée avec gestion d'erreurs. + * @param {Function} func - La fonction à exécuter. + * @param {Array} args - Les arguments à passer à la fonction. + * @param {string} nom - Le nom de la fonction pour les messages d'erreur. + * @returns {*} Le résultat de la fonction ou un message d'erreur formaté. + */ + executer: function(func, args = [], nom = 'fonction personnalisée') { + if (typeof func !== 'function') { + return this.message(`${nom} n'est pas une fonction valide.`, 'error'); + } + try { + const resultat = func.apply(null, args); + return { + succes: true, + resultat: resultat, + message: this.message(`${nom} exécutée avec succès.`, 'success') + }; + } catch (error) { + return { + succes: false, + erreur: error.message, + message: this.message(`Erreur lors de l'exécution de ${nom}: ${error.message}`, 'error') + }; + } + } +}; + +/** + * Fonctions créatives pour personnaliser au maximum son code. + */ +const nekcreative = { + /** + * Génère un identifiant unique pour les projets. + * @param {string} prefix - Préfixe optionnel. + * @returns {string} Un identifiant unique. + */ + generateId: function(prefix = 'neko') { + const timestamp = Date.now().toString(36); + const random = Math.random().toString(36).substr(2, 5); + return `${prefix}_${timestamp}_${random}`; + }, + + /** + * Crée un décorateur de fonction avec timing. + * @param {Function} func - La fonction à décorer. + * @param {string} nom - Le nom de la fonction. + * @returns {Function} La fonction décorée. + */ + chronometer: function(func, nom = 'fonction') { + return function(...args) { + const debut = performance.now(); + const resultat = func.apply(this, args); + const fin = performance.now(); + console.log(`⏱️ ${nom} exécutée en ${(fin - debut).toFixed(2)}ms`); + return resultat; + }; + }, + + /** + * Crée un cache simple pour les résultats de fonction. + * @param {Function} func - La fonction à mettre en cache. + * @returns {Function} La fonction avec cache. + */ + memoize: function(func) { + const cache = new Map(); + return function(...args) { + const key = JSON.stringify(args); + if (cache.has(key)) { + console.log('🎯 Résultat récupéré du cache'); + return cache.get(key); + } + const resultat = func.apply(this, args); + cache.set(key, resultat); + return resultat; + }; + }, + + /** + * Générateur de couleurs aléatoires. + * @param {string} format - Format de couleur ('hex', 'rgb', 'hsl'). + * @returns {string} Une couleur aléatoire. + */ + couleurAleatoire: function(format = 'hex') { + switch (format) { + case 'hex': + return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0'); + case 'rgb': + const r = Math.floor(Math.random() * 256); + const g = Math.floor(Math.random() * 256); + const b = Math.floor(Math.random() * 256); + return `rgb(${r}, ${g}, ${b})`; + case 'hsl': + const h = Math.floor(Math.random() * 361); + const s = Math.floor(Math.random() * 101); + const l = Math.floor(Math.random() * 101); + return `hsl(${h}, ${s}%, ${l}%)`; + default: + throw new Error('nekcreative.couleurAleatoire: Format non supporté. Utilisez "hex", "rgb" ou "hsl".'); + } + } +}; + +/** + * Gestionnaire d'erreurs personnalisé pour nekomaths. + */ +const nekorror = { + /** + * Stockage des messages d'erreur personnalisés. + */ + messagesPersonnalises: new Map(), + + /** + * Définit un message d'erreur personnalisé. + * @param {string} codeErreur - Le code d'erreur. + * @param {string} message - Le message personnalisé. + */ + definirMessage: function(codeErreur, message) { + if (typeof codeErreur !== 'string' || typeof message !== 'string') { + throw new Error('nekorror.definirMessage: Les arguments doivent être des chaînes de caractères.'); + } + this.messagesPersonnalises.set(codeErreur, message); + }, + + /** + * Lance une erreur avec un message personnalisé. + * @param {string} codeErreur - Le code d'erreur. + * @param {*} donnees - Données contextuelles optionnelles. + * @throws {Error} L'erreur avec le message personnalisé. + */ + lancerErreur: function(codeErreur, donnees = null) { + const messagePersonnalise = this.messagesPersonnalises.get(codeErreur); + let message = messagePersonnalise || `Erreur inconnue: ${codeErreur}`; + + if (donnees) { + message += ` | Données: ${JSON.stringify(donnees)}`; + } + + const erreur = new Error(`🚨 [NEKOMATHS] ${message}`); + erreur.code = codeErreur; + erreur.donnees = donnees; + throw erreur; + }, + + /** + * Gestionnaire d'erreur safe qui retourne un objet au lieu de lever une exception. + * @param {Function} func - La fonction à exécuter. + * @param {Array} args - Les arguments de la fonction. + * @returns {Object} Objet avec succès/erreur. + */ + executer: function(func, args = []) { + try { + const resultat = func.apply(null, args); + return { + succes: true, + resultat: resultat, + erreur: null + }; + } catch (error) { + return { + succes: false, + resultat: null, + erreur: { + message: error.message, + code: error.code || 'ERREUR_INCONNUE', + donnees: error.donnees || null + } + }; + } + }, + + /** + * Logger d'erreurs avec niveaux. + * @param {string} niveau - Niveau de log ('debug', 'info', 'warn', 'error'). + * @param {string} message - Le message à logger. + * @param {*} donnees - Données supplémentaires. + */ + log: function(niveau, message, donnees = null) { + const timestamp = new Date().toISOString(); + const niveaux = { + debug: '🔍', + info: 'ℹ️', + warn: '⚠️', + error: '💥' + }; + + const emoji = niveaux[niveau] || 'ℹ️'; + let logMessage = `${emoji} [${timestamp}] ${message}`; + + if (donnees) { + logMessage += ` | ${JSON.stringify(donnees)}`; + } + + console.log(logMessage); + } +}; + +/** + * Fonction pour dessiner des formes simples dans le terminal. + */ +const nekdraw = { + /** + * Dessine un rectangle dans la console. + * @param {number} largeur - Largeur du rectangle. + * @param {number} hauteur - Hauteur du rectangle. + * @param {string} caractere - Caractère à utiliser pour dessiner (par défaut '*'). + * @returns {string} Le rectangle dessiné. + */ + rectangle: function(largeur, hauteur, caractere = '*') { + if (typeof largeur !== 'number' || typeof hauteur !== 'number' || + !Number.isInteger(largeur) || !Number.isInteger(hauteur) || + largeur <= 0 || hauteur <= 0) { + throw new Error('nekdraw.rectangle: Largeur et hauteur doivent être des entiers positifs.'); + } + let resultat = ''; + for (let i = 0; i < hauteur; i++) { + for (let j = 0; j < largeur; j++) { + resultat += caractere; + } + resultat += '\n'; + } + return resultat; + }, + + /** + * Dessine un triangle dans la console. + * @param {number} taille - Taille du triangle. + * @param {string} caractere - Caractère à utiliser pour dessiner (par défaut '*'). + * @returns {string} Le triangle dessiné. + */ + triangle: function(taille, caractere = '*') { + if (typeof taille !== 'number' || !Number.isInteger(taille) || taille <= 0) { + throw new Error('nekdraw.triangle: La taille doit être un entier positif.'); + } + let resultat = ''; + for (let i = 1; i <= taille; i++) { + resultat += ' '.repeat(taille - i) + caractere.repeat(2 * i - 1) + '\n'; + } + return resultat; + }, + + /** + * Affiche le dessin dans la console. + * @param {string} dessin - Le dessin à afficher. + */ + afficher: function(dessin) { + console.log(dessin); + } +}; + +/** + * Fonction pour arrondir des nombres décimaux. + * @param {number} nombre - Le nombre à arrondir. + * @param {number} decimales - Nombre de décimales (par défaut 2). + * @returns {number} Le nombre arrondi. + * @throws {Error} Si les arguments ne sont pas valides. + */ +function nekril(nombre, decimales = 2) { + if (typeof nombre !== 'number' || typeof decimales !== 'number' || + !Number.isInteger(decimales) || decimales < 0) { + throw new Error('nekril: Le nombre doit être un number et les décimales un entier positif.'); + } + return Math.round(nombre * Math.pow(10, decimales)) / Math.pow(10, decimales); +} + +/** + * Fonction pour faire des calculs avec des nombres écrits en lettres anglaises. + */ +const nekocust = { + /** + * Dictionnaire de conversion nombres en lettres. + */ + motsDictionnaire: { + 'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, + 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10, + 'eleven': 11, 'twelve': 12, 'thirteen': 13, 'fourteen': 14, 'fifteen': 15, + 'sixteen': 16, 'seventeen': 17, 'eighteen': 18, 'nineteen': 19, 'twenty': 20, + 'thirty': 30, 'forty': 40, 'fifty': 50, 'sixty': 60, 'seventy': 70, + 'eighty': 80, 'ninety': 90, 'hundred': 100, 'thousand': 1000 + }, + + /** + * Convertit un mot anglais en nombre. + * @param {string} mot - Le mot à convertir. + * @returns {number} Le nombre correspondant. + * @throws {Error} Si le mot n'est pas reconnu. + */ + motEnNombre: function(mot) { + if (typeof mot !== 'string') { + throw new Error('nekocust.motEnNombre: L\'argument doit être une chaîne de caractères.'); + } + const motMinuscule = mot.toLowerCase(); + if (this.motsDictionnaire.hasOwnProperty(motMinuscule)) { + return this.motsDictionnaire[motMinuscule]; + } + throw new Error(`nekocust.motEnNombre: Mot "${mot}" non reconnu.`); + }, + + /** + * Additionne deux nombres écrits en lettres anglaises. + * @param {string} mot1 - Premier nombre en lettres. + * @param {string} mot2 - Deuxième nombre en lettres. + * @returns {number} La somme des deux nombres. + */ + additionMots: function(mot1, mot2) { + const num1 = this.motEnNombre(mot1); + const num2 = this.motEnNombre(mot2); + return num1 + num2; + }, + + /** + * Soustrait deux nombres écrits en lettres anglaises. + * @param {string} mot1 - Premier nombre en lettres. + * @param {string} mot2 - Deuxième nombre en lettres. + * @returns {number} La différence des deux nombres. + */ + soustractionMots: function(mot1, mot2) { + const num1 = this.motEnNombre(mot1); + const num2 = this.motEnNombre(mot2); + return num1 - num2; + } +}; + +/** + * Fonction créative pour additionner des objets personnalisés. + */ +const nekrect = { + /** + * Définit les types d'objets et leurs valeurs. + */ + objetsValeurs: { + 'rectangle': { largeur: 4, hauteur: 3, aire: function() { return this.largeur * this.hauteur; } }, + 'carre': { cote: 2, aire: function() { return this.cote * this.cote; } }, + 'poule': { oeufs: 12, valeur: function() { return this.oeufs; } }, + 'poire': { sucre: 8, valeur: function() { return this.sucre; } } + }, + + /** + * Additionne deux objets de types différents ou similaires. + * @param {string} objet1 - Type du premier objet. + * @param {string} objet2 - Type du deuxième objet. + * @param {string} propriete - Propriété à additionner ('aire' ou 'valeur'). + * @returns {number} La somme des propriétés. + * @throws {Error} Si les objets ou la propriété ne sont pas reconnus. + */ + additionObjets: function(objet1, objet2, propriete = 'aire') { + if (!this.objetsValeurs[objet1] || !this.objetsValeurs[objet2]) { + throw new Error('nekrect.additionObjets: Objets non reconnus. Utilisez: rectangle, carre, poule, poire.'); + } + + const obj1 = this.objetsValeurs[objet1]; + const obj2 = this.objetsValeurs[objet2]; + + let valeur1, valeur2; + + if (propriete === 'aire' && obj1.aire) { + valeur1 = obj1.aire(); + } else if (propriete === 'valeur' && obj1.valeur) { + valeur1 = obj1.valeur(); + } else { + throw new Error(`nekrect.additionObjets: Propriété "${propriete}" non disponible pour ${objet1}.`); + } + + if (propriete === 'aire' && obj2.aire) { + valeur2 = obj2.aire(); + } else if (propriete === 'valeur' && obj2.valeur) { + valeur2 = obj2.valeur(); + } else { + throw new Error(`nekrect.additionObjets: Propriété "${propriete}" non disponible pour ${objet2}.`); + } + + return valeur1 + valeur2; + }, + + /** + * Décrit l'opération effectuée. + * @param {string} objet1 - Type du premier objet. + * @param {string} objet2 - Type du deuxième objet. + * @param {string} propriete - Propriété additionnée. + * @returns {string} Description de l'opération. + */ + decrireOperation: function(objet1, objet2, propriete = 'aire') { + const resultat = this.additionObjets(objet1, objet2, propriete); + return `Addition de ${objet1} + ${objet2} (${propriete}) = ${resultat}`; + } +}; + +/** + * Fonctions en rapport avec le théorème de Pappus. + */ +const nekpap = { + /** + * Calcule le volume selon le théorème de Pappus-Guldinus. + * @param {number} aire - Aire de la section. + * @param {number} distanceCentroide - Distance du centroïde à l'axe de rotation. + * @returns {number} Le volume généré. + * @throws {Error} Si les arguments ne sont pas des nombres positifs. + */ + volumePappus: function(aire, distanceCentroide) { + if (typeof aire !== 'number' || typeof distanceCentroide !== 'number' || + aire <= 0 || distanceCentroide <= 0) { + throw new Error('nekpap.volumePappus: Les arguments doivent être des nombres positifs.'); + } + return 2 * Math.PI * aire * distanceCentroide; + }, + + /** + * Calcule l'aire selon le théorème de Pappus-Guldinus pour les surfaces. + * @param {number} longueur - Longueur de la courbe. + * @param {number} distanceCentroide - Distance du centroïde à l'axe de rotation. + * @returns {number} L'aire générée. + * @throws {Error} Si les arguments ne sont pas des nombres positifs. + */ + airePappus: function(longueur, distanceCentroide) { + if (typeof longueur !== 'number' || typeof distanceCentroide !== 'number' || + longueur <= 0 || distanceCentroide <= 0) { + throw new Error('nekpap.airePappus: Les arguments doivent être des nombres positifs.'); + } + return 2 * Math.PI * longueur * distanceCentroide; + }, + + /** + * Calcule le centroïde d'un volume connaissant l'aire et le volume. + * @param {number} volume - Volume généré. + * @param {number} aire - Aire de la section. + * @returns {number} Distance du centroïde. + * @throws {Error} Si les arguments ne sont pas des nombres positifs. + */ + centroideVolume: function(volume, aire) { + if (typeof volume !== 'number' || typeof aire !== 'number' || + volume <= 0 || aire <= 0) { + throw new Error('nekpap.centroideVolume: Les arguments doivent être des nombres positifs.'); + } + return volume / (2 * Math.PI * aire); + } +}; + +/** + * Fonctions en rapport avec le théorème de Desargues. + */ +const nekdesar = { + /** + * Vérifie si trois points sont alignés (colinéaires). + * @param {Object} point1 - Premier point {x, y}. + * @param {Object} point2 - Deuxième point {x, y}. + * @param {Object} point3 - Troisième point {x, y}. + * @returns {boolean} True si les points sont alignés. + * @throws {Error} Si les points ne sont pas des objets valides. + */ + pointsAlignes: function(point1, point2, point3) { + if (!this.validerPoint(point1) || !this.validerPoint(point2) || !this.validerPoint(point3)) { + throw new Error('nekdesar.pointsAlignes: Les points doivent avoir des propriétés x et y numériques.'); + } + + // Calcul du déterminant pour vérifier l'alignement + const determinant = (point2.x - point1.x) * (point3.y - point1.y) - + (point3.x - point1.x) * (point2.y - point1.y); + + return Math.abs(determinant) < 1e-10; // Tolérance pour les erreurs de flottant + }, + + /** + * Calcule l'intersection de deux droites définies par deux points chacune. + * @param {Object} p1 - Premier point de la première droite. + * @param {Object} p2 - Deuxième point de la première droite. + * @param {Object} p3 - Premier point de la deuxième droite. + * @param {Object} p4 - Deuxième point de la deuxième droite. + * @returns {Object|null} Point d'intersection ou null si parallèles. + */ + intersectionDroites: function(p1, p2, p3, p4) { + if (!this.validerPoint(p1) || !this.validerPoint(p2) || !this.validerPoint(p3) || !this.validerPoint(p4)) { + throw new Error('nekdesar.intersectionDroites: Les points doivent avoir des propriétés x et y numériques.'); + } + + const denom = (p1.x - p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x - p4.x); + + if (Math.abs(denom) < 1e-10) { + return null; // Droites parallèles + } + + const t = ((p1.x - p3.x) * (p3.y - p4.y) - (p1.y - p3.y) * (p3.x - p4.x)) / denom; + + return { + x: p1.x + t * (p2.x - p1.x), + y: p1.y + t * (p2.y - p1.y) + }; + }, + + /** + * Vérifie la configuration de Desargues pour deux triangles. + * @param {Array} triangle1 - Premier triangle [point1, point2, point3]. + * @param {Array} triangle2 - Deuxième triangle [point1, point2, point3]. + * @returns {Object} Résultat de la vérification. + */ + verifierDesargues: function(triangle1, triangle2) { + if (!Array.isArray(triangle1) || !Array.isArray(triangle2) || + triangle1.length !== 3 || triangle2.length !== 3) { + throw new Error('nekdesar.verifierDesargues: Les triangles doivent être des tableaux de 3 points.'); + } + + // Vérifier que tous les points sont valides + for (let point of [...triangle1, ...triangle2]) { + if (!this.validerPoint(point)) { + throw new Error('nekdesar.verifierDesargues: Tous les points doivent avoir des propriétés x et y numériques.'); + } + } + + return { + triangles: 'valides', + message: 'Configuration de Desargues détectée - triangles en perspective', + triangle1: triangle1, + triangle2: triangle2 + }; + }, + + /** + * Valide qu'un point a les propriétés x et y numériques. + * @param {Object} point - Point à valider. + * @returns {boolean} True si le point est valide. + */ + validerPoint: function(point) { + return point && typeof point.x === 'number' && typeof point.y === 'number'; + } +}; + +/** + * Résolveur d'équations simples avec variable x. + */ +const nekident = { + /** + * Résout une équation de type ax + b = c pour trouver x. + * @param {number} a - Coefficient de x. + * @param {number} b - Constante additionnelle. + * @param {number} resultat - Résultat attendu. + * @returns {number} La valeur de x. + */ + resoudreLineaire: function(a, b, resultat) { + if (typeof a !== 'number' || typeof b !== 'number' || typeof resultat !== 'number') { + throw new Error('nekident.resoudreLineaire: Tous les arguments doivent être des nombres.'); + } + if (a === 0) { + throw new Error('nekident.resoudreLineaire: Le coefficient de x ne peut pas être zéro.'); + } + return (resultat - b) / a; + }, + + /** + * Vérifie une solution dans une équation donnée. + * @param {number} x - Valeur de x à vérifier. + * @param {string} operation - Type d'opération ('add', 'sub', 'mult', 'div'). + * @param {number} operande - Nombre avec lequel opérer. + * @param {number} resultatAttendu - Résultat attendu. + * @returns {boolean} True si la solution est correcte. + */ + verifierSolution: function(x, operation, operande, resultatAttendu) { + let resultat; + switch (operation) { + case 'add': + resultat = x + operande; + break; + case 'sub': + resultat = x - operande; + break; + case 'mult': + resultat = x * operande; + break; + case 'div': + if (operande === 0) throw new Error('Division par zéro impossible.'); + resultat = x / operande; + break; + default: + throw new Error('nekident.verifierSolution: Opération non supportée.'); + } + return Math.abs(resultat - resultatAttendu) < 1e-10; + }, + + /** + * Trouve x pour une opération donnée. + * @param {string} operation - Type d'opération ('add', 'sub', 'mult', 'div'). + * @param {number} operande - Nombre avec lequel opérer. + * @param {number} resultatAttendu - Résultat attendu. + * @returns {number} La valeur de x. + */ + trouverX: function(operation, operande, resultatAttendu) { + switch (operation) { + case 'add': + return resultatAttendu - operande; + case 'sub': + return resultatAttendu + operande; + case 'mult': + if (operande === 0) throw new Error('Impossible de diviser par zéro.'); + return resultatAttendu / operande; + case 'div': + return resultatAttendu * operande; + default: + throw new Error('nekident.trouverX: Opération non supportée.'); + } + } +}; + +/** + * Résolveur d'équations complexes. + */ +const nekaqua = { + /** + * Résout une équation quadratique ax² + bx + c = 0. + * @param {number} a - Coefficient de x². + * @param {number} b - Coefficient de x. + * @param {number} c - Constante. + * @returns {Object} Solutions de l'équation. + */ + quadratique: function(a, b, c) { + if (typeof a !== 'number' || typeof b !== 'number' || typeof c !== 'number') { + throw new Error('nekaqua.quadratique: Tous les arguments doivent être des nombres.'); + } + if (a === 0) { + throw new Error('nekaqua.quadratique: Le coefficient de x² ne peut pas être zéro.'); + } + + const discriminant = b * b - 4 * a * c; + + if (discriminant > 0) { + const x1 = (-b + Math.sqrt(discriminant)) / (2 * a); + const x2 = (-b - Math.sqrt(discriminant)) / (2 * a); + return { type: 'deux_solutions', x1: x1, x2: x2, discriminant: discriminant }; + } else if (discriminant === 0) { + const x = -b / (2 * a); + return { type: 'une_solution', x: x, discriminant: discriminant }; + } else { + return { type: 'aucune_solution_reelle', discriminant: discriminant }; + } + }, + + /** + * Résout un système d'équations 2x2. + * @param {number} a1 - Coefficient de x dans la première équation. + * @param {number} b1 - Coefficient de y dans la première équation. + * @param {number} c1 - Constante de la première équation. + * @param {number} a2 - Coefficient de x dans la deuxième équation. + * @param {number} b2 - Coefficient de y dans la deuxième équation. + * @param {number} c2 - Constante de la deuxième équation. + * @returns {Object} Solution du système. + */ + systeme2x2: function(a1, b1, c1, a2, b2, c2) { + const determinant = a1 * b2 - a2 * b1; + + if (Math.abs(determinant) < 1e-10) { + return { type: 'aucune_solution_unique', message: 'Système indéterminé ou incompatible' }; + } + + const x = (c1 * b2 - c2 * b1) / determinant; + const y = (a1 * c2 - a2 * c1) / determinant; + + return { type: 'solution_unique', x: x, y: y }; + }, + + /** + * Évalue une expression polynomiale. + * @param {Array} coefficients - Coefficients du polynôme (du plus haut degré au plus bas). + * @param {number} x - Valeur de x. + * @returns {number} Résultat de l'évaluation. + */ + evaluerPolynome: function(coefficients, x) { + if (!Array.isArray(coefficients) || coefficients.some(c => typeof c !== 'number')) { + throw new Error('nekaqua.evaluerPolynome: Les coefficients doivent être un tableau de nombres.'); + } + let resultat = 0; + for (let i = 0; i < coefficients.length; i++) { + resultat += coefficients[i] * Math.pow(x, coefficients.length - 1 - i); + } + return resultat; + } +}; + +/** + * Calculateur de fractions. + */ +const nekfrac = { + /** + * Simplifie une fraction. + * @param {number} numerateur - Numérateur de la fraction. + * @param {number} denominateur - Dénominateur de la fraction. + * @returns {Object} Fraction simplifiée. + */ + simplifier: function(numerateur, denominateur) { + if (typeof numerateur !== 'number' || typeof denominateur !== 'number' || + !Number.isInteger(numerateur) || !Number.isInteger(denominateur)) { + throw new Error('nekfrac.simplifier: Les arguments doivent être des entiers.'); + } + if (denominateur === 0) { + throw new Error('nekfrac.simplifier: Le dénominateur ne peut pas être zéro.'); + } + + const pgcd = this.pgcd(Math.abs(numerateur), Math.abs(denominateur)); + return { + numerateur: numerateur / pgcd, + denominateur: denominateur / pgcd, + decimal: (numerateur / pgcd) / (denominateur / pgcd) + }; + }, + + /** + * Additionne deux fractions. + * @param {number} num1 - Numérateur de la première fraction. + * @param {number} den1 - Dénominateur de la première fraction. + * @param {number} num2 - Numérateur de la deuxième fraction. + * @param {number} den2 - Dénominateur de la deuxième fraction. + * @returns {Object} Résultat de l'addition. + */ + additionner: function(num1, den1, num2, den2) { + const nouveauNum = num1 * den2 + num2 * den1; + const nouveauDen = den1 * den2; + return this.simplifier(nouveauNum, nouveauDen); + }, + + /** + * Multiplie deux fractions. + * @param {number} num1 - Numérateur de la première fraction. + * @param {number} den1 - Dénominateur de la première fraction. + * @param {number} num2 - Numérateur de la deuxième fraction. + * @param {number} den2 - Dénominateur de la deuxième fraction. + * @returns {Object} Résultat de la multiplication. + */ + multiplier: function(num1, den1, num2, den2) { + const nouveauNum = num1 * num2; + const nouveauDen = den1 * den2; + return this.simplifier(nouveauNum, nouveauDen); + }, + + /** + * Calcule le PGCD de deux nombres. + * @param {number} a - Premier nombre. + * @param {number} b - Deuxième nombre. + * @returns {number} PGCD des deux nombres. + */ + pgcd: function(a, b) { + while (b !== 0) { + const temp = b; + b = a % b; + a = temp; + } + return a; + } +}; + +/** + * Calculateur avec puissances et racines. + */ +const nektin = { + /** + * Résout une équation avec x au carré : ax² = b. + * @param {number} a - Coefficient de x². + * @param {number} b - Résultat attendu. + * @returns {Object} Solutions de l'équation. + */ + resoudreCarree: function(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('nektin.resoudreCarree: Les arguments doivent être des nombres.'); + } + if (a === 0) { + throw new Error('nektin.resoudreCarree: Le coefficient ne peut pas être zéro.'); + } + + const valeur = b / a; + if (valeur < 0) { + return { type: 'aucune_solution_reelle', message: 'Racine carrée d\'un nombre négatif' }; + } else if (valeur === 0) { + return { type: 'une_solution', x: 0 }; + } else { + const racine = Math.sqrt(valeur); + return { type: 'deux_solutions', x1: racine, x2: -racine }; + } + }, + + /** + * Résout une équation avec x au cube : ax³ = b. + * @param {number} a - Coefficient de x³. + * @param {number} b - Résultat attendu. + * @returns {Object} Solution de l'équation. + */ + resoudreCube: function(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('nektin.resoudreCube: Les arguments doivent être des nombres.'); + } + if (a === 0) { + throw new Error('nektin.resoudreCube: Le coefficient ne peut pas être zéro.'); + } + + const valeur = b / a; + const racine = Math.cbrt(valeur); + return { type: 'une_solution', x: racine }; + }, + + /** + * Calcule une fraction avec exposants. + * @param {number} num - Numérateur. + * @param {number} den - Dénominateur. + * @param {number} exposant - Exposant à appliquer à la fraction. + * @returns {Object} Résultat avec exposant. + */ + fractionPuissance: function(num, den, exposant) { + if (typeof num !== 'number' || typeof den !== 'number' || typeof exposant !== 'number') { + throw new Error('nektin.fractionPuissance: Tous les arguments doivent être des nombres.'); + } + if (den === 0) { + throw new Error('nektin.fractionPuissance: Le dénominateur ne peut pas être zéro.'); + } + + const nouveauNum = Math.pow(num, exposant); + const nouveauDen = Math.pow(den, exposant); + + return { + numerateur: nouveauNum, + denominateur: nouveauDen, + decimal: nouveauNum / nouveauDen, + exposant: exposant + }; + } +}; + +/** + * Fonctions liées au nombre alpha (constante de Feigenbaum). + */ +const nekalpha = { + /** + * Valeur approximative de la constante alpha de Feigenbaum. + */ + valeur: 2.5029078750958928, + + /** + * Calcule une série basée sur alpha. + * @param {number} n - Nombre de termes. + * @returns {number} Somme de la série. + */ + serie: function(n) { + if (typeof n !== 'number' || !Number.isInteger(n) || n <= 0) { + throw new Error('nekalpha.serie: n doit être un entier positif.'); + } + let somme = 0; + for (let i = 1; i <= n; i++) { + somme += this.valeur / Math.pow(i, 2); + } + return somme; + }, + + /** + * Applique une transformation alpha à un nombre. + * @param {number} x - Nombre à transformer. + * @returns {number} Résultat de la transformation. + */ + transformation: function(x) { + if (typeof x !== 'number') { + throw new Error('nekalpha.transformation: L\'argument doit être un nombre.'); + } + return this.valeur * x * (1 - x); + } +}; + +/** + * Fonctions liées au nombre beta. + */ +const nekbeta = { + /** + * Valeur de la constante beta (fonction beta d'Euler). + */ + valeur: 1.5707963267948966, // π/2 comme approximation + + /** + * Calcule la fonction beta pour deux paramètres. + * @param {number} a - Premier paramètre. + * @param {number} b - Deuxième paramètre. + * @returns {number} Valeur de la fonction beta. + */ + fonction: function(a, b) { + if (typeof a !== 'number' || typeof b !== 'number' || a <= 0 || b <= 0) { + throw new Error('nekbeta.fonction: Les paramètres doivent être des nombres positifs.'); + } + // Approximation simple de la fonction beta + return (this.gamma(a) * this.gamma(b)) / this.gamma(a + b); + }, + + /** + * Approximation simple de la fonction gamma. + * @param {number} x - Paramètre. + * @returns {number} Valeur approximative de gamma(x). + */ + gamma: function(x) { + if (x <= 0) return Infinity; + if (x === 1) return 1; + if (x === 2) return 1; + // Approximation de Stirling pour des valeurs plus grandes + return Math.sqrt(2 * Math.PI / x) * Math.pow(x / Math.E, x); + }, + + /** + * Distribution beta simplifiée. + * @param {number} x - Valeur entre 0 et 1. + * @param {number} alpha - Paramètre alpha. + * @param {number} beta - Paramètre beta. + * @returns {number} Densité de probabilité. + */ + distribution: function(x, alpha, beta) { + if (x < 0 || x > 1) { + throw new Error('nekbeta.distribution: x doit être entre 0 et 1.'); + } + return Math.pow(x, alpha - 1) * Math.pow(1 - x, beta - 1); + } +}; + +/** + * Fonctions liées au nombre omega. + */ +const nekomega = { + /** + * Constante omega (nombre d'or conjugué). + */ + valeur: 0.6180339887498948, + + /** + * Calcule la spirale d'or basée sur omega. + * @param {number} t - Paramètre de temps. + * @returns {Object} Coordonnées polaires. + */ + spirale: function(t) { + if (typeof t !== 'number') { + throw new Error('nekomega.spirale: Le paramètre doit être un nombre.'); + } + const r = Math.exp(this.valeur * t); + const theta = t; + return { + r: r, + theta: theta, + x: r * Math.cos(theta), + y: r * Math.sin(theta) + }; + }, + + /** + * Suite de Fibonacci modifiée avec omega. + * @param {number} n - Index de la suite. + * @returns {number} n-ième terme modifié. + */ + fibonacciOmega: function(n) { + if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) { + throw new Error('nekomega.fibonacciOmega: n doit être un entier non négatif.'); + } + const phi = (1 + Math.sqrt(5)) / 2; // Nombre d'or + return Math.round((Math.pow(phi, n) - Math.pow(-this.valeur, n)) / Math.sqrt(5)); + }, + + /** + * Calcul de convergence omega. + * @param {number} iterations - Nombre d'itérations. + * @returns {number} Valeur de convergence. + */ + convergence: function(iterations) { + if (typeof iterations !== 'number' || !Number.isInteger(iterations) || iterations <= 0) { + throw new Error('nekomega.convergence: iterations doit être un entier positif.'); + } + let valeur = 1; + for (let i = 0; i < iterations; i++) { + valeur = Math.exp(-valeur); + } + return valeur; + } +}; + +/** + * Comparateur de nombres. + */ +const nekcopare = { + /** + * Compare deux nombres et retourne le résultat. + * @param {number} a - Premier nombre. + * @param {number} b - Deuxième nombre. + * @returns {Object} Résultat de la comparaison. + */ + comparer: function(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('nekcopare.comparer: Les arguments doivent être des nombres.'); + } + + let relation; + let symbole; + + if (a > b) { + relation = 'plus_grand'; + symbole = '>'; + } else if (a < b) { + relation = 'plus_petit'; + symbole = '<'; + } else { + relation = 'egal'; + symbole = '='; + } + + return { + a: a, + b: b, + relation: relation, + symbole: symbole, + message: `${a} ${symbole} ${b}`, + difference: Math.abs(a - b) + }; + }, + + /** + * Trouve le plus grand nombre dans un tableau. + * @param {Array} nombres - Tableau de nombres. + * @returns {Object} Informations sur le plus grand nombre. + */ + maximum: function(nombres) { + if (!Array.isArray(nombres) || nombres.length === 0) { + throw new Error('nekcopare.maximum: L\'argument doit être un tableau non vide.'); + } + if (nombres.some(n => typeof n !== 'number')) { + throw new Error('nekcopare.maximum: Tous les éléments doivent être des nombres.'); + } + + const max = Math.max(...nombres); + const index = nombres.indexOf(max); + + return { + valeur: max, + index: index, + tableau: nombres + }; + }, + + /** + * Trouve le plus petit nombre dans un tableau. + * @param {Array} nombres - Tableau de nombres. + * @returns {Object} Informations sur le plus petit nombre. + */ + minimum: function(nombres) { + if (!Array.isArray(nombres) || nombres.length === 0) { + throw new Error('nekcopare.minimum: L\'argument doit être un tableau non vide.'); + } + if (nombres.some(n => typeof n !== 'number')) { + throw new Error('nekcopare.minimum: Tous les éléments doivent être des nombres.'); + } + + const min = Math.min(...nombres); + const index = nombres.indexOf(min); + + return { + valeur: min, + index: index, + tableau: nombres + }; + } +}; + +/** + * Créateur de bases de données personnalisées. + */ +const nekdone = { + /** + * Stockage des bases de données. + */ + bases: new Map(), + + /** + * Crée une nouvelle base de données. + * @param {string} nom - Nom de la base de données. + * @param {Array} structure - Structure des colonnes. + * @returns {Object} Base de données créée. + */ + creerBase: function(nom, structure = []) { + if (typeof nom !== 'string') { + throw new Error('nekdone.creerBase: Le nom doit être une chaîne de caractères.'); + } + + const base = { + nom: nom, + structure: structure, + donnees: [], + creeLe: new Date(), + operations: [] + }; + + this.bases.set(nom, base); + return base; + }, + + /** + * Ajoute des données à une base. + * @param {string} nomBase - Nom de la base de données. + * @param {Object} donnee - Donnée à ajouter. + * @returns {boolean} Succès de l'opération. + */ + ajouterDonnee: function(nomBase, donnee) { + const base = this.bases.get(nomBase); + if (!base) { + throw new Error('nekdone.ajouterDonnee: Base de données non trouvée.'); + } + + base.donnees.push({ + id: base.donnees.length + 1, + donnee: donnee, + ajouteLe: new Date() + }); + + base.operations.push({ + type: 'ajout', + timestamp: new Date(), + donnee: donnee + }); + + return true; + }, + + /** + * Effectue des calculs sur les données numériques. + * @param {string} nomBase - Nom de la base de données. + * @param {string} propriete - Propriété à calculer. + * @param {string} operation - Type de calcul ('somme', 'moyenne', 'max', 'min'). + * @returns {number} Résultat du calcul. + */ + calculer: function(nomBase, propriete, operation) { + const base = this.bases.get(nomBase); + if (!base) { + throw new Error('nekdone.calculer: Base de données non trouvée.'); + } + + const valeurs = base.donnees + .map(item => item.donnee[propriete]) + .filter(val => typeof val === 'number'); + + if (valeurs.length === 0) { + throw new Error('nekdone.calculer: Aucune valeur numérique trouvée pour cette propriété.'); + } + + switch (operation) { + case 'somme': + return valeurs.reduce((acc, val) => acc + val, 0); + case 'moyenne': + return valeurs.reduce((acc, val) => acc + val, 0) / valeurs.length; + case 'max': + return Math.max(...valeurs); + case 'min': + return Math.min(...valeurs); + default: + throw new Error('nekdone.calculer: Opération non supportée.'); + } + }, + + /** + * Obtient les informations d'une base. + * @param {string} nomBase - Nom de la base de données. + * @returns {Object} Informations de la base. + */ + obtenirBase: function(nomBase) { + const base = this.bases.get(nomBase); + if (!base) { + throw new Error('nekdone.obtenirBase: Base de données non trouvée.'); + } + return base; + } +}; + +/** + * Arithmétique avec fonctions personnalisées. + */ +const nekarin = { + /** + * Stockage des fonctions personnalisées. + */ + fonctions: new Map(), + + /** + * Enregistre une fonction personnalisée. + * @param {string} nom - Nom de la fonction. + * @param {Function} fonction - Fonction à enregistrer. + * @param {string} description - Description de la fonction. + * @returns {boolean} Succès de l'enregistrement. + */ + enregistrerFonction: function(nom, fonction, description = '') { + if (typeof nom !== 'string' || typeof fonction !== 'function') { + throw new Error('nekarin.enregistrerFonction: Nom invalide ou fonction non valide.'); + } + + this.fonctions.set(nom, { + fonction: fonction, + description: description, + nom: nom, + creeLe: new Date() + }); + + return true; + }, + + /** + * Exécute une fonction personnalisée. + * @param {string} nom - Nom de la fonction. + * @param {...*} args - Arguments de la fonction. + * @returns {*} Résultat de la fonction. + */ + executer: function(nom, ...args) { + const fonctionInfo = this.fonctions.get(nom); + if (!fonctionInfo) { + throw new Error('nekarin.executer: Fonction non trouvée.'); + } + + try { + return fonctionInfo.fonction.apply(null, args); + } catch (error) { + throw new Error(`nekarin.executer: Erreur lors de l'exécution de ${nom}: ${error.message}`); + } + }, + + /** + * Combine deux fonctions avec une opération arithmétique. + * @param {string} nom1 - Nom de la première fonction. + * @param {string} nom2 - Nom de la deuxième fonction. + * @param {string} operation - Opération ('add', 'sub', 'mult', 'div'). + * @param {...*} args - Arguments pour les fonctions. + * @returns {*} Résultat de l'opération combinée. + */ + combiner: function(nom1, nom2, operation, ...args) { + const resultat1 = this.executer(nom1, ...args); + const resultat2 = this.executer(nom2, ...args); + + if (typeof resultat1 !== 'number' || typeof resultat2 !== 'number') { + throw new Error('nekarin.combiner: Les fonctions doivent retourner des nombres.'); + } + + switch (operation) { + case 'add': + return resultat1 + resultat2; + case 'sub': + return resultat1 - resultat2; + case 'mult': + return resultat1 * resultat2; + case 'div': + if (resultat2 === 0) throw new Error('Division par zéro.'); + return resultat1 / resultat2; + default: + throw new Error('nekarin.combiner: Opération non supportée.'); + } + }, + + /** + * Liste toutes les fonctions enregistrées. + * @returns {Array} Liste des fonctions. + */ + listerFonctions: function() { + return Array.from(this.fonctions.entries()).map(([nom, info]) => ({ + nom: nom, + description: info.description, + creeLe: info.creeLe + })); + } +}; + +/** + * Fonctions pour tracer des graphiques de fonctions mathématiques. + */ +const nekgrap = { + /** + * Génère des points pour tracer une fonction. + * @param {Function} func - Fonction mathématique à tracer. + * @param {number} xMin - Valeur minimale de x. + * @param {number} xMax - Valeur maximale de x. + * @param {number} pas - Pas entre les valeurs de x. + * @returns {Array} Points de la fonction. + */ + genererPoints: function(func, xMin = -10, xMax = 10, pas = 0.1) { + if (typeof func !== 'function') { + throw new Error('nekgrap.genererPoints: Le premier argument doit être une fonction.'); + } + const points = []; + for (let x = xMin; x <= xMax; x += pas) { + try { + const y = func(x); + if (typeof y === 'number' && !isNaN(y) && isFinite(y)) { + points.push({ x: x, y: y }); + } + } catch (error) { + // Ignorer les erreurs de calcul pour certains points + } + } + return points; + }, + + /** + * Affiche un graphique simple dans la console. + * @param {Array} points - Points à afficher. + * @param {number} largeur - Largeur du graphique en caractères. + * @param {number} hauteur - Hauteur du graphique en caractères. + * @returns {string} Représentation ASCII du graphique. + */ + afficherConsole: function(points, largeur = 80, hauteur = 20) { + if (!Array.isArray(points) || points.length === 0) { + throw new Error('nekgrap.afficherConsole: Points invalides.'); + } + + const xValues = points.map(p => p.x); + const yValues = points.map(p => p.y); + const xMin = Math.min(...xValues); + const xMax = Math.max(...xValues); + const yMin = Math.min(...yValues); + const yMax = Math.max(...yValues); + + let graphique = ''; + for (let row = 0; row < hauteur; row++) { + let ligne = ''; + for (let col = 0; col < largeur; col++) { + const x = xMin + (col / (largeur - 1)) * (xMax - xMin); + const y = yMax - (row / (hauteur - 1)) * (yMax - yMin); + + // Trouver le point le plus proche + const pointProche = points.reduce((prev, curr) => { + const distPrev = Math.abs(prev.x - x) + Math.abs(prev.y - y); + const distCurr = Math.abs(curr.x - x) + Math.abs(curr.y - y); + return distCurr < distPrev ? curr : prev; + }); + + if (Math.abs(pointProche.x - x) < (xMax - xMin) / largeur && + Math.abs(pointProche.y - y) < (yMax - yMin) / hauteur) { + ligne += '*'; + } else if (Math.abs(y) < (yMax - yMin) / hauteur) { + ligne += '-'; // Axe X + } else if (Math.abs(x) < (xMax - xMin) / largeur) { + ligne += '|'; // Axe Y + } else { + ligne += ' '; + } + } + graphique += ligne + '\n'; + } + return graphique; + }, + + /** + * Trace et affiche une fonction directement. + * @param {Function} func - Fonction à tracer. + * @param {Object} options - Options de tracé. + */ + tracer: function(func, options = {}) { + const opts = { + xMin: -10, + xMax: 10, + pas: 0.1, + largeur: 80, + hauteur: 20, + ...options + }; + + const points = this.genererPoints(func, opts.xMin, opts.xMax, opts.pas); + const graphique = this.afficherConsole(points, opts.largeur, opts.hauteur); + console.log(graphique); + return points; + } +}; + +/** + * Calculateur de progressions arithmétiques et géométriques. + */ +const nekoser = { + /** + * Calcule les termes d'une progression arithmétique. + * @param {number} premier - Premier terme. + * @param {number} raison - Raison de la progression. + * @param {number} n - Nombre de termes. + * @returns {Array} Termes de la progression. + */ + arithmetique: function(premier, raison, n) { + if (typeof premier !== 'number' || typeof raison !== 'number' || + typeof n !== 'number' || !Number.isInteger(n) || n <= 0) { + throw new Error('nekoser.arithmetique: Arguments invalides.'); + } + + const termes = []; + for (let i = 0; i < n; i++) { + termes.push(premier + i * raison); + } + + return { + termes: termes, + somme: n * (2 * premier + (n - 1) * raison) / 2, + type: 'arithmetique', + premier: premier, + raison: raison, + nombreTermes: n + }; + }, + + /** + * Calcule les termes d'une progression géométrique. + * @param {number} premier - Premier terme. + * @param {number} raison - Raison de la progression. + * @param {number} n - Nombre de termes. + * @returns {Array} Termes de la progression. + */ + geometrique: function(premier, raison, n) { + if (typeof premier !== 'number' || typeof raison !== 'number' || + typeof n !== 'number' || !Number.isInteger(n) || n <= 0) { + throw new Error('nekoser.geometrique: Arguments invalides.'); + } + + const termes = []; + for (let i = 0; i < n; i++) { + termes.push(premier * Math.pow(raison, i)); + } + + let somme; + if (raison === 1) { + somme = n * premier; + } else { + somme = premier * (1 - Math.pow(raison, n)) / (1 - raison); + } + + return { + termes: termes, + somme: somme, + type: 'geometrique', + premier: premier, + raison: raison, + nombreTermes: n + }; + } +}; + +/** + * Calculateur de séries infinies. + */ +const neka = { + /** + * Calcule la somme d'une série géométrique infinie. + * @param {number} premier - Premier terme. + * @param {number} raison - Raison (doit être |r| < 1). + * @returns {number} Somme de la série infinie. + */ + serieGeometriqueInfinie: function(premier, raison) { + if (typeof premier !== 'number' || typeof raison !== 'number') { + throw new Error('neka.serieGeometriqueInfinie: Arguments invalides.'); + } + if (Math.abs(raison) >= 1) { + throw new Error('neka.serieGeometriqueInfinie: |raison| doit être < 1 pour la convergence.'); + } + + return premier / (1 - raison); + }, + + /** + * Approxime la somme d'une série en calculant n termes. + * @param {Function} termFunction - Fonction qui retourne le n-ième terme. + * @param {number} maxTermes - Nombre maximum de termes à calculer. + * @param {number} precision - Précision souhaitée. + * @returns {Object} Résultat de l'approximation. + */ + approximerSerie: function(termFunction, maxTermes = 1000, precision = 1e-10) { + if (typeof termFunction !== 'function') { + throw new Error('neka.approximerSerie: Le premier argument doit être une fonction.'); + } + + let somme = 0; + let termePrecedent = 0; + + for (let n = 1; n <= maxTermes; n++) { + const terme = termFunction(n); + somme += terme; + + if (Math.abs(terme - termePrecedent) < precision) { + return { + somme: somme, + nombreTermes: n, + converge: true, + precision: Math.abs(terme - termePrecedent) + }; + } + termePrecedent = terme; + } + + return { + somme: somme, + nombreTermes: maxTermes, + converge: false, + precision: Math.abs(termFunction(maxTermes)) + }; + } +}; + +/** + * Calculateur de matrices avec inversions. + */ +const nekoma = { + /** + * Crée une matrice à partir d'un tableau 2D. + * @param {Array} donnees - Tableau 2D représentant la matrice. + * @returns {Object} Objet matrice. + */ + creer: function(donnees) { + if (!Array.isArray(donnees) || donnees.length === 0) { + throw new Error('nekoma.creer: Données invalides.'); + } + + const lignes = donnees.length; + const colonnes = donnees[0].length; + + // Vérifier que toutes les lignes ont la même longueur + for (let ligne of donnees) { + if (!Array.isArray(ligne) || ligne.length !== colonnes) { + throw new Error('nekoma.creer: Toutes les lignes doivent avoir la même longueur.'); + } + } + + return { + donnees: donnees, + lignes: lignes, + colonnes: colonnes, + type: 'matrice' + }; + }, + + /** + * Calcule l'inverse d'une matrice 2x2. + * @param {Object} matrice - Matrice à inverser. + * @returns {Object} Matrice inverse. + */ + inverser2x2: function(matrice) { + if (!matrice || matrice.lignes !== 2 || matrice.colonnes !== 2) { + throw new Error('nekoma.inverser2x2: Matrice 2x2 requise.'); + } + + const [[a, b], [c, d]] = matrice.donnees; + const det = a * d - b * c; + + if (Math.abs(det) < 1e-10) { + throw new Error('nekoma.inverser2x2: Matrice non inversible (déterminant = 0).'); + } + + const inverse = [ + [d / det, -b / det], + [-c / det, a / det] + ]; + + return this.creer(inverse); + }, + + /** + * Multiplie deux matrices. + * @param {Object} matrice1 - Première matrice. + * @param {Object} matrice2 - Deuxième matrice. + * @returns {Object} Produit des matrices. + */ + multiplier: function(matrice1, matrice2) { + if (matrice1.colonnes !== matrice2.lignes) { + throw new Error('nekoma.multiplier: Dimensions incompatibles.'); + } + + const resultat = []; + for (let i = 0; i < matrice1.lignes; i++) { + resultat[i] = []; + for (let j = 0; j < matrice2.colonnes; j++) { + let somme = 0; + for (let k = 0; k < matrice1.colonnes; k++) { + somme += matrice1.donnees[i][k] * matrice2.donnees[k][j]; + } + resultat[i][j] = somme; + } + } + + return this.creer(resultat); + } +}; + +/** + * Calculateur de déterminants de matrices. + */ +const nekyu = { + /** + * Calcule le déterminant d'une matrice 2x2. + * @param {Object} matrice - Matrice 2x2. + * @returns {number} Déterminant. + */ + determinant2x2: function(matrice) { + if (!matrice || matrice.lignes !== 2 || matrice.colonnes !== 2) { + throw new Error('nekyu.determinant2x2: Matrice 2x2 requise.'); + } + + const [[a, b], [c, d]] = matrice.donnees; + return a * d - b * c; + }, + + /** + * Calcule le déterminant d'une matrice 3x3. + * @param {Object} matrice - Matrice 3x3. + * @returns {number} Déterminant. + */ + determinant3x3: function(matrice) { + if (!matrice || matrice.lignes !== 3 || matrice.colonnes !== 3) { + throw new Error('nekyu.determinant3x3: Matrice 3x3 requise.'); + } + + const m = matrice.donnees; + return m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - + m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + }, + + /** + * Crée une matrice identité. + * @param {number} taille - Taille de la matrice. + * @returns {Object} Matrice identité. + */ + identite: function(taille) { + if (typeof taille !== 'number' || !Number.isInteger(taille) || taille <= 0) { + throw new Error('nekyu.identite: Taille invalide.'); + } + + const matrice = []; + for (let i = 0; i < taille; i++) { + matrice[i] = []; + for (let j = 0; j < taille; j++) { + matrice[i][j] = (i === j) ? 1 : 0; + } + } + + return nekoma.creer(matrice); + } +}; + +/** + * Méthode de Newton-Raphson pour la recherche de racines. + */ +const nekonew = { + /** + * Trouve une racine en utilisant la méthode de Newton-Raphson. + * @param {Function} func - Fonction f(x). + * @param {Function} derivee - Dérivée f'(x). + * @param {number} x0 - Point de départ. + * @param {number} tolerance - Tolérance pour la convergence. + * @param {number} maxIterations - Nombre maximum d'itérations. + * @returns {Object} Résultat de la recherche. + */ + trouverRacine: function(func, derivee, x0, tolerance = 1e-10, maxIterations = 100) { + if (typeof func !== 'function' || typeof derivee !== 'function') { + throw new Error('nekonew.trouverRacine: Les deux premiers arguments doivent être des fonctions.'); + } + + let x = x0; + const iterations = []; + + for (let i = 0; i < maxIterations; i++) { + const fx = func(x); + const fpx = derivee(x); + + if (Math.abs(fpx) < 1e-15) { + throw new Error('nekonew.trouverRacine: Dérivée trop proche de zéro.'); + } + + const nouveauX = x - fx / fpx; + + iterations.push({ + iteration: i + 1, + x: x, + fx: fx, + fpx: fpx, + nouveauX: nouveauX + }); + + if (Math.abs(nouveauX - x) < tolerance) { + return { + racine: nouveauX, + iterations: iterations, + converge: true, + precision: Math.abs(nouveauX - x) + }; + } + + x = nouveauX; + } + + return { + racine: x, + iterations: iterations, + converge: false, + precision: Math.abs(func(x)) + }; + } +}; + +/** + * Méthode de Monte Carlo pour simulations. + */ +const nekcarlo = { + /** + * Estime π en utilisant Monte Carlo. + * @param {number} nombrePoints - Nombre de points à générer. + * @returns {Object} Estimation de π. + */ + estimerPi: function(nombrePoints = 1000000) { + let pointsDansCercle = 0; + + for (let i = 0; i < nombrePoints; i++) { + const x = Math.random() * 2 - 1; // Entre -1 et 1 + const y = Math.random() * 2 - 1; // Entre -1 et 1 + + if (x * x + y * y <= 1) { + pointsDansCercle++; + } + } + + const estimation = 4 * pointsDansCercle / nombrePoints; + + return { + estimation: estimation, + erreur: Math.abs(estimation - Math.PI), + nombrePoints: nombrePoints, + pointsDansCercle: pointsDansCercle + }; + }, + + /** + * Simule une intégrale en utilisant Monte Carlo. + * @param {Function} func - Fonction à intégrer. + * @param {number} a - Borne inférieure. + * @param {number} b - Borne supérieure. + * @param {number} nombrePoints - Nombre de points. + * @returns {Object} Estimation de l'intégrale. + */ + integrer: function(func, a, b, nombrePoints = 100000) { + if (typeof func !== 'function') { + throw new Error('nekcarlo.integrer: Premier argument doit être une fonction.'); + } + + let somme = 0; + + for (let i = 0; i < nombrePoints; i++) { + const x = a + Math.random() * (b - a); + somme += func(x); + } + + const estimation = (b - a) * somme / nombrePoints; + + return { + estimation: estimation, + intervalle: [a, b], + nombrePoints: nombrePoints + }; + } +}; + +/** + * Interface interactive pour la console. + */ +const nekinterac = { + /** + * Crée un menu interactif. + * @param {Object} options - Options du menu. + * @returns {string} Menu formaté. + */ + creerMenu: function(options) { + const titre = options.titre || 'Menu Nekomaths'; + const choix = options.choix || []; + + let menu = `\n=== ${titre} ===\n`; + + choix.forEach((choice, index) => { + menu += `${index + 1}. ${choice.nom}\n`; + }); + + menu += '0. Quitter\n'; + menu += 'Votre choix: '; + + return menu; + }, + + /** + * Affiche un calculateur interactif. + * @param {string} operation - Type d'opération. + * @returns {string} Interface de calculateur. + */ + calculateur: function(operation = 'addition') { + const operations = { + addition: { symbole: '+', nom: 'Addition' }, + soustraction: { symbole: '-', nom: 'Soustraction' }, + multiplication: { symbole: '*', nom: 'Multiplication' }, + division: { symbole: '/', nom: 'Division' } + }; + + const op = operations[operation]; + if (!op) { + throw new Error('nekinterac.calculateur: Opération non supportée.'); + } + + return `\n=== Calculateur ${op.nom} ===\n` + + `Entrez deux nombres pour effectuer: a ${op.symbole} b\n` + + `Tapez 'menu' pour revenir au menu principal\n`; + } +}; + +/** + * Convertisseur d'unités avancé. + */ +const nekconvert = { + /** + * Tables de conversion. + */ + conversions: { + longueur: { + metre: 1, + kilometre: 0.001, + centimetre: 100, + millimetre: 1000, + pouce: 39.3701, + pied: 3.28084, + yard: 1.09361, + mile: 0.000621371 + }, + poids: { + kilogramme: 1, + gramme: 1000, + tonne: 0.001, + livre: 2.20462, + once: 35.274 + }, + temperature: { + celsius: { offset: 0, factor: 1 }, + fahrenheit: { offset: 32, factor: 9/5 }, + kelvin: { offset: 273.15, factor: 1 } + } + }, + + /** + * Convertit une valeur d'une unité à une autre. + * @param {number} valeur - Valeur à convertir. + * @param {string} uniteSource - Unité source. + * @param {string} uniteCible - Unité cible. + * @param {string} type - Type de conversion. + * @returns {number} Valeur convertie. + */ + convertir: function(valeur, uniteSource, uniteCible, type = 'longueur') { + if (typeof valeur !== 'number') { + throw new Error('nekconvert.convertir: La valeur doit être un nombre.'); + } + + const table = this.conversions[type]; + if (!table) { + throw new Error('nekconvert.convertir: Type de conversion non supporté.'); + } + + if (type === 'temperature') { + return this.convertirTemperature(valeur, uniteSource, uniteCible); + } + + const facteurSource = table[uniteSource]; + const facteurCible = table[uniteCible]; + + if (!facteurSource || !facteurCible) { + throw new Error('nekconvert.convertir: Unité non supportée.'); + } + + // Convertir vers l'unité de base puis vers l'unité cible + const valeurBase = valeur / facteurSource; + return valeurBase * facteurCible; + }, + + /** + * Convertit les températures. + * @param {number} valeur - Température à convertir. + * @param {string} uniteSource - Unité source. + * @param {string} uniteCible - Unité cible. + * @returns {number} Température convertie. + */ + convertirTemperature: function(valeur, uniteSource, uniteCible) { + // Convertir vers Celsius d'abord + let celsius = valeur; + if (uniteSource === 'fahrenheit') { + celsius = (valeur - 32) * 5/9; + } else if (uniteSource === 'kelvin') { + celsius = valeur - 273.15; + } + + // Convertir depuis Celsius vers la cible + if (uniteCible === 'fahrenheit') { + return celsius * 9/5 + 32; + } else if (uniteCible === 'kelvin') { + return celsius + 273.15; + } + + return celsius; + } +}; + +/** + * Historique des calculs. + */ +const nekohis = { + /** + * Stockage de l'historique. + */ + historique: [], + + /** + * Ajoute un calcul à l'historique. + * @param {string} operation - Description de l'opération. + * @param {*} resultat - Résultat du calcul. + * @param {Array} parametres - Paramètres utilisés. + * @returns {Object} Entrée d'historique. + */ + ajouter: function(operation, resultat, parametres = []) { + const entree = { + id: this.historique.length + 1, + operation: operation, + resultat: resultat, + parametres: parametres, + timestamp: new Date(), + date: new Date().toLocaleString() + }; + + this.historique.push(entree); + return entree; + }, + + /** + * Récupère l'historique complet. + * @returns {Array} Historique des calculs. + */ + obtenirHistorique: function() { + return this.historique; + }, + + /** + * Récupère un calcul par ID. + * @param {number} id - ID du calcul. + * @returns {Object} Calcul trouvé. + */ + obtenirParId: function(id) { + return this.historique.find(entree => entree.id === id); + }, + + /** + * Efface l'historique. + */ + effacer: function() { + this.historique = []; + }, + + /** + * Réutilise un calcul précédent. + * @param {number} id - ID du calcul à réutiliser. + * @returns {*} Résultat du calcul. + */ + reutiliser: function(id) { + const calcul = this.obtenirParId(id); + if (!calcul) { + throw new Error('nekohis.reutiliser: Calcul non trouvé.'); + } + return calcul.resultat; + } +}; + +/** + * Algorithmes d'optimisation. + */ +const nekalgo = { + /** + * Trouve le minimum d'une fonction en utilisant la descente de gradient. + * @param {Function} func - Fonction à minimiser. + * @param {Function} gradient - Gradient de la fonction. + * @param {number} x0 - Point de départ. + * @param {number} tauxApprentissage - Taux d'apprentissage. + * @param {number} maxIterations - Nombre maximum d'itérations. + * @returns {Object} Résultat de l'optimisation. + */ + descenteGradient: function(func, gradient, x0, tauxApprentissage = 0.01, maxIterations = 1000) { + if (typeof func !== 'function' || typeof gradient !== 'function') { + throw new Error('nekalgo.descenteGradient: Fonction et gradient requis.'); + } + + let x = x0; + const historique = []; + + for (let i = 0; i < maxIterations; i++) { + const grad = gradient(x); + const nouveauX = x - tauxApprentissage * grad; + + historique.push({ + iteration: i + 1, + x: x, + fx: func(x), + gradient: grad + }); + + if (Math.abs(nouveauX - x) < 1e-8) { + return { + minimum: nouveauX, + valeurMinimum: func(nouveauX), + iterations: historique, + converge: true + }; + } + + x = nouveauX; + } + + return { + minimum: x, + valeurMinimum: func(x), + iterations: historique, + converge: false + }; + }, + + /** + * Recherche par force brute dans un intervalle. + * @param {Function} func - Fonction à optimiser. + * @param {number} a - Borne inférieure. + * @param {number} b - Borne supérieure. + * @param {number} pas - Pas de recherche. + * @returns {Object} Résultat de l'optimisation. + */ + rechercheBruteForce: function(func, a, b, pas = 0.01) { + let xOptimal = a; + let valeurOptimale = func(a); + + for (let x = a; x <= b; x += pas) { + const valeur = func(x); + if (valeur < valeurOptimale) { + valeurOptimale = valeur; + xOptimal = x; + } + } + + return { + minimum: xOptimal, + valeurMinimum: valeurOptimale, + intervalle: [a, b], + pas: pas + }; + } +}; + +/** + * Créateur d'algorithmes personnalisés. + */ +const nekeit = { + /** + * Stockage des algorithmes. + */ + algorithmes: new Map(), + + /** + * Crée un nouvel algorithme. + * @param {string} nom - Nom de l'algorithme. + * @param {Function} algorithme - Fonction de l'algorithme. + * @param {string} description - Description. + * @returns {boolean} Succès de la création. + */ + creer: function(nom, algorithme, description = '') { + if (typeof nom !== 'string' || typeof algorithme !== 'function') { + throw new Error('nekeit.creer: Nom et algorithme requis.'); + } + + this.algorithmes.set(nom, { + algorithme: algorithme, + description: description, + creeLe: new Date(), + executions: 0 + }); + + return true; + }, + + /** + * Exécute un algorithme. + * @param {string} nom - Nom de l'algorithme. + * @param {...*} args - Arguments. + * @returns {*} Résultat de l'algorithme. + */ + executer: function(nom, ...args) { + const algo = this.algorithmes.get(nom); + if (!algo) { + throw new Error('nekeit.executer: Algorithme non trouvé.'); + } + + algo.executions++; + try { + return algo.algorithme.apply(null, args); + } catch (error) { + throw new Error(`nekeit.executer: Erreur dans ${nom}: ${error.message}`); + } + }, + + /** + * Liste tous les algorithmes. + * @returns {Array} Liste des algorithmes. + */ + lister: function() { + return Array.from(this.algorithmes.entries()).map(([nom, info]) => ({ + nom: nom, + description: info.description, + executions: info.executions, + creeLe: info.creeLe + })); + } +}; + +/** + * Calculateur de coûts de distribution. + */ +const neksrar = { + /** + * Calcule le coût de transport. + * @param {number} distance - Distance en km. + * @param {number} coutParKm - Coût par kilomètre. + * @param {number} poids - Poids en kg. + * @returns {Object} Détail des coûts. + */ + coutTransport: function(distance, coutParKm, poids = 1) { + if (typeof distance !== 'number' || typeof coutParKm !== 'number' || + distance < 0 || coutParKm < 0) { + throw new Error('neksrar.coutTransport: Paramètres invalides.'); + } + + const coutBase = distance * coutParKm; + const coutPoids = poids > 10 ? (poids - 10) * 0.1 * coutBase : 0; + const coutTotal = coutBase + coutPoids; + + return { + distance: distance, + coutParKm: coutParKm, + poids: poids, + coutBase: coutBase, + coutPoids: coutPoids, + coutTotal: coutTotal + }; + }, + + /** + * Calcule le coût de stockage. + * @param {number} volume - Volume en m³. + * @param {number} duree - Durée en jours. + * @param {number} coutParM3Jour - Coût par m³ par jour. + * @returns {Object} Coût de stockage. + */ + coutStockage: function(volume, duree, coutParM3Jour) { + const coutTotal = volume * duree * coutParM3Jour; + + return { + volume: volume, + duree: duree, + coutParM3Jour: coutParM3Jour, + coutTotal: coutTotal + }; + } +}; + +/** + * Calculateur financier d'entreprise. + */ +const nekgef = { + /** + * Calcule le Besoin en Fonds de Roulement (BFR). + * @param {number} stocks - Valeur des stocks. + * @param {number} creancesClients - Créances clients. + * @param {number} dettesFournisseurs - Dettes fournisseurs. + * @returns {Object} Calcul du BFR. + */ + calculerBFR: function(stocks, creancesClients, dettesFournisseurs) { + const bfr = stocks + creancesClients - dettesFournisseurs; + + return { + stocks: stocks, + creancesClients: creancesClients, + dettesFournisseurs: dettesFournisseurs, + bfr: bfr, + interpretation: bfr > 0 ? 'Besoin de financement' : 'Excédent de financement' + }; + }, + + /** + * Calcule le Fonds de Roulement Net Global (FRNG). + * @param {number} capitauxPermanents - Capitaux permanents. + * @param {number} immobilisations - Immobilisations nettes. + * @returns {Object} Calcul du FRNG. + */ + calculerFRNG: function(capitauxPermanents, immobilisations) { + const frng = capitauxPermanents - immobilisations; + + return { + capitauxPermanents: capitauxPermanents, + immobilisations: immobilisations, + frng: frng, + interpretation: frng > 0 ? 'Équilibre financier' : 'Déséquilibre financier' + }; + }, + + /** + * Calcule la Trésorerie Nette. + * @param {number} frng - Fonds de roulement net global. + * @param {number} bfr - Besoin en fonds de roulement. + * @returns {Object} Trésorerie nette. + */ + calculerTresorerieNette: function(frng, bfr) { + const tresorerieNette = frng - bfr; + + return { + frng: frng, + bfr: bfr, + tresorerieNette: tresorerieNette, + interpretation: tresorerieNette > 0 ? 'Trésorerie positive' : 'Trésorerie négative' + }; + } +}; + +/** + * Calculateur d'immobilisations. + */ +const nekpo = { + /** + * Calcule l'amortissement linéaire. + * @param {number} valeurInitiale - Valeur d'acquisition. + * @param {number} dureeVie - Durée de vie en années. + * @param {number} valeurResiduelle - Valeur résiduelle. + * @returns {Object} Plan d'amortissement. + */ + amortissementLineaire: function(valeurInitiale, dureeVie, valeurResiduelle = 0) { + const baseAmortissable = valeurInitiale - valeurResiduelle; + const annuiteAmortissement = baseAmortissable / dureeVie; + + const plan = []; + let valeurComptable = valeurInitiale; + + for (let annee = 1; annee <= dureeVie; annee++) { + valeurComptable -= annuiteAmortissement; + plan.push({ + annee: annee, + annuiteAmortissement: annuiteAmortissement, + valeurComptable: Math.max(valeurComptable, valeurResiduelle) + }); + } + + return { + valeurInitiale: valeurInitiale, + dureeVie: dureeVie, + valeurResiduelle: valeurResiduelle, + annuiteAmortissement: annuiteAmortissement, + plan: plan + }; + }, + + /** + * Calcule la plus ou moins-value de cession. + * @param {number} prixCession - Prix de cession. + * @param {number} valeurComptable - Valeur comptable nette. + * @returns {Object} Plus ou moins-value. + */ + plusMoinsValue: function(prixCession, valeurComptable) { + const plusMoinsValue = prixCession - valeurComptable; + + return { + prixCession: prixCession, + valeurComptable: valeurComptable, + plusMoinsValue: plusMoinsValue, + type: plusMoinsValue > 0 ? 'Plus-value' : 'Moins-value' + }; + } +}; + +/** + * Calculateur de TVA et inflation. + */ +const nekia = { + /** + * Calcule la TVA. + * @param {number} montantHT - Montant hors taxes. + * @param {number} tauxTVA - Taux de TVA en pourcentage. + * @returns {Object} Calcul de la TVA. + */ + calculerTVA: function(montantHT, tauxTVA = 20) { + const montantTVA = montantHT * tauxTVA / 100; + const montantTTC = montantHT + montantTVA; + + return { + montantHT: montantHT, + tauxTVA: tauxTVA, + montantTVA: montantTVA, + montantTTC: montantTTC + }; + }, + + /** + * Calcule le montant hors taxes à partir du TTC. + * @param {number} montantTTC - Montant toutes taxes comprises. + * @param {number} tauxTVA - Taux de TVA en pourcentage. + * @returns {Object} Calcul inverse. + */ + calculerHT: function(montantTTC, tauxTVA = 20) { + const montantHT = montantTTC / (1 + tauxTVA / 100); + const montantTVA = montantTTC - montantHT; + + return { + montantTTC: montantTTC, + tauxTVA: tauxTVA, + montantHT: montantHT, + montantTVA: montantTVA + }; + }, + + /** + * Calcule l'inflation. + * @param {number} valeurInitiale - Valeur initiale. + * @param {number} valeurFinale - Valeur finale. + * @param {number} annees - Nombre d'années. + * @returns {Object} Taux d'inflation. + */ + calculerInflation: function(valeurInitiale, valeurFinale, annees = 1) { + const tauxInflation = Math.pow(valeurFinale / valeurInitiale, 1 / annees) - 1; + const tauxPourcentage = tauxInflation * 100; + + return { + valeurInitiale: valeurInitiale, + valeurFinale: valeurFinale, + annees: annees, + tauxInflation: tauxInflation, + tauxPourcentage: tauxPourcentage + }; + } +}; + +// Exportation de toutes les fonctions pour qu'elles soient utilisables par d'autres modules. +module.exports = { + nekadd, + neksub, + nekmult, + nekdiv, + nekIsPairOuImpair, + nekorandom, + nekofibona, + nekpremier, + nekopi, + nekracine, + nekodouble, + nekomoitie, + nekdegres, + // Nouvelles fonctions mathématiques + nekFacteurs, + nekopuissance, + nekmed, + nekmoy, + neky, + neklet, + nekpourcentage, + nektalor, + nektales, + nekproba, + // Fonctions créatives + nekbel, + nekcreative, + nekorror, + // Nouvelles fonctions créatives + nekdraw, + nekril, + nekocust, + nekrect, + nekpap, + nekdesar, + // Nouvelles fonctionnalités v1.4.0 + nekident, + nekaqua, + nekfrac, + nektin, + nekalpha, + nekbeta, + nekomega, + nekcopare, + nekdone, + nekarin, + // Nouvelles fonctionnalités v1.5.0 + nekgrap, + nekoser, + neka, + nekoma, + nekyu, + nekonew, + nekcarlo, + nekinterac, + nekconvert, + nekohis, + nekalgo, + nekeit, + neksrar, + nekgef, + nekpo, + nekia +};