From a7d20a0c905e8e4c0a856e956f2952c6ece3c503 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Thu, 25 Jun 2026 17:30:36 +0300 Subject: [PATCH] =?UTF-8?q?feat(trainer):=20=D0=9D=D0=9E=D0=94=20=D0=B8=20?= =?UTF-8?q?=D0=9D=D0=9E=D0=9A=20(5-6=20=D0=BA=D0=BB)=20+=20=D1=84=D1=83?= =?UTF-8?q?=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20gcd/lcm=20=D0=B2=20SimExpr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SimExpr: добавлены whitelisted-функции gcd (алгоритм Евклида) и lcm (арность 2), защищены от NaN/0/отрицательных. Аддитивно — существующие спеки SimForge/Quantik не затронуты - НОВАЯ тема НОД и НОК: gcd-pair (НОД), lcm-pair (НОК). Числа строятся как g·m и g·k (общий множитель) → НОД нетривиален; gcd/lcm считаются и проверяются движком - 60 генераторов, 20 тем; смоук движка 1154/1154, страница 40/40; gcd(36,24)=12, lcm(4,6)=12 верны; эмодзи 0 Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/js/labs/_sim_expr.js | 18 ++++++++++++++-- frontend/js/trainer/generators.js | 36 ++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/frontend/js/labs/_sim_expr.js b/frontend/js/labs/_sim_expr.js index f397228..64c636f 100644 --- a/frontend/js/labs/_sim_expr.js +++ b/frontend/js/labs/_sim_expr.js @@ -38,7 +38,8 @@ asin: 1, acos: 1, atan: 1, arcsin: 1, arccos: 1, arctan: 1, arctg: 1, sqrt: 1, abs: 1, exp: 1, ln: 1, log: -2, log2: 1, log10: 1, floor: 1, ceil: 1, round: 1, sign: 1, - min: -1, max: -1, mod: 2, atan2: 2, pow: 2, hypot: -1 + min: -1, max: -1, mod: 2, atan2: 2, pow: 2, hypot: -1, + gcd: 2, lcm: 2 }; // Реализации. Все защищены от исключений на уровне evaluate (домены проверяются @@ -60,7 +61,20 @@ floor: Math.floor, ceil: Math.ceil, round: Math.round, sign: Math.sign, min: Math.min, max: Math.max, mod: function (a, b) { return b === 0 ? 0 : a % b; }, - atan2: Math.atan2, pow: Math.pow, hypot: Math.hypot + atan2: Math.atan2, pow: Math.pow, hypot: Math.hypot, + // НОД (алгоритм Евклида) и НОК — целочисленные, защищены от NaN/0/отрицательных + gcd: function (a, b) { + a = Math.abs(Math.round(a)); b = Math.abs(Math.round(b)); + if (!isFinite(a) || !isFinite(b)) return 0; + while (b) { var t = a % b; a = b; b = t; } + return a; + }, + lcm: function (a, b) { + a = Math.abs(Math.round(a)); b = Math.abs(Math.round(b)); + if (!a || !b || !isFinite(a) || !isFinite(b)) return 0; + var x = a, y = b; while (y) { var t = x % y; x = y; y = t; } + return a / x * b; + } }; var CONSTANTS = { pi: Math.PI, PI: Math.PI, e: Math.E, E: Math.E, tau: Math.PI * 2 }; diff --git a/frontend/js/trainer/generators.js b/frontend/js/trainer/generators.js index 29c8fa3..83e8d27 100644 --- a/frontend/js/trainer/generators.js +++ b/frontend/js/trainer/generators.js @@ -32,6 +32,7 @@ { key: 'systems', label: 'Системы', subject: 'algebra', grade: 7, order: 8 }, { key: 'quadratic', label: 'Квадратные', subject: 'algebra', grade: 8, order: 9 }, { key: 'progressions', label: 'Прогрессии', subject: 'algebra', grade: 9, order: 10 }, + { key: 'gcd-lcm', label: 'НОД и НОК', subject: 'algebra', grade: 5, order: 1.4 }, { key: 'fractions', label: 'Дроби', subject: 'algebra', grade: 5, order: 1.5 }, { key: 'decimals', label: 'Десятичные', subject: 'algebra', grade: 5, order: 1.6 }, { key: 'negatives', label: 'Отрицательные', subject: 'algebra', grade: 6, order: 1.7 }, @@ -833,6 +834,38 @@ ] }, + /* ═══ Тема: НОД и НОК (5–6 класс) ═══ + Числа строим как g·m и g·k (общий множитель g) → НОД ≥ g, не тривиален. + gcd/lcm — функции SimExpr (алгоритм Евклида), считаются и проверяются движком. */ + + /* наибольший общий делитель */ + { + id: 'gcd-pair', topic: 'gcd-lcm', order: 1, subject: 'algebra', grade: 5, kind: 'compute', + title: 'НОД двух чисел', + pick: { g: [2, 9], m: [2, 8], k: [2, 8] }, constraint: 'm != k', + derive: { a: 'g*m', b: 'g*k', val: 'gcd(a, b)' }, + lhs: 'x', rhs: 'gcd({a}, {b})', display: 'Найдите наибольший общий делитель (НОД) чисел {a} и {b}.', + answerVar: 'x', answer: 'val', integerAnswer: true, + solution: [ + { note: 'Разложите числа на простые множители; НОД — произведение общих множителей в наименьших степенях (или алгоритм Евклида).', tex: '' }, + { note: 'Получаем:', tex: 'x = {ans}' } + ] + }, + + /* наименьшее общее кратное */ + { + id: 'lcm-pair', topic: 'gcd-lcm', order: 2, subject: 'algebra', grade: 6, kind: 'compute', + title: 'НОК двух чисел', + pick: { g: [2, 6], m: [2, 7], k: [2, 7] }, constraint: 'm != k', + derive: { a: 'g*m', b: 'g*k', val: 'lcm(a, b)' }, + lhs: 'x', rhs: 'lcm({a}, {b})', display: 'Найдите наименьшее общее кратное (НОК) чисел {a} и {b}.', + answerVar: 'x', answer: 'val', integerAnswer: true, + solution: [ + { note: 'НОК = произведение чисел, делённое на их НОД: НОК(a, b) = a·b ÷ НОД(a, b).', tex: '' }, + { note: 'Получаем:', tex: 'x = {ans}' } + ] + }, + /* ═══ Тема: Десятичные дроби (5 класс) ═══ Строим через десятые/сотые (целые ÷10, ÷100) → ответ печатается чисто. */ @@ -955,7 +988,8 @@ 'area-parallelogram': 2, 'area-trapezoid': 3, 'area-rhombus': 2, // Геометрия — Многоугольники / Подобие 'poly-angles-sum': 1, 'poly-regular-angle': 2, 'sim-side': 1, 'sim-perimeter': 2, - // Дроби / Десятичные / Отрицательные + // НОД/НОК / Дроби / Десятичные / Отрицательные + 'gcd-pair': 1, 'lcm-pair': 2, 'frac-of-number': 1, 'frac-add-same': 2, 'dec-add': 1, 'dec-sub': 1, 'dec-mult': 2, 'neg-add': 1, 'neg-sub': 2, 'neg-mult': 2