Skill: integers
Practice: Integers & Order of Operations
Add, subtract, multiply, and divide integers with sign rules, then evaluate expressions where negatives meet PEMDAS.
1 Practice
Untimed practice with hints and full worked solutions. Every problem is generated fresh.
How to enter answers
- Type integers plainly:
-2,12. - Use the hyphen-minus on your keyboard (
-), not the longer dash. - Fractions are not needed here — every answer is an integer.
2 Problem types
The generator mixes these types at random.
Add integers
Same sign: add and keep. Different: subtract, keep the bigger one.
Subtract integers
Minus a negative is plus a positive.
Absolute value
Distance from zero — never negative.
Multiply integers
Same signs → positive; different → negative.
Divide integers
Same sign rules as multiplication.
Order of operations
Negatives inside PEMDAS; watch −a² vs (−a)².
// __QCORE_BEGIN__
var QGEN = (function(){
'use strict';
function ri(rng, lo, hi){ return lo + Math.floor(rng() * (hi - lo + 1)); }
function pick(rng, a){ return a[Math.floor(rng() * a.length)]; }
function sgn(n){ return n < 0 ? '(' + n + ')' : String(n); }
function mhtml(s){ return '' + s + ''; }
/* recursive-descent evaluator for integer expressions with ^ and unary minus */
function makeParser(toks){
var pos = 0;
function peek(){ return pos < toks.length ? toks[pos] : null; }
function next(){ return toks[pos++]; }
function parseE(){
var v = parseT();
while (peek() === '+' || peek() === '-'){ var op = next(); var r = parseT(); v = op === '+' ? v + r : v - r; }
return v;
}
function parseT(){
var v = parseF();
while (peek() === '*' || peek() === '/'){ var op = next(); var r = parseF(); v = op === '*' ? v * r : v / r; }
return v;
}
function parseF(){
if (peek() === '-' || peek() === '+'){ var op = next(); var v = parseF(); return op === '-' ? -v : v; }
return parseP();
}
function parseP(){
var base = parseA();
if (peek() === '^'){ next(); var e = parseF(); return Math.pow(base, e); }
return base;
}
function parseA(){
var t = next();
if (t === '('){ var v = parseE(); next(); return v; }
return parseFloat(t);
}
return {parse:function(){ var v = parseE(); return v; }};
}
function tokenize(s){
var toks = [], i = 0;
while (i < s.length){
var c = s[i];
if (c === ' '){ i++; continue; }
if ('+-*/^()'.indexOf(c) >= 0){ toks.push(c); i++; continue; }
var j = i;
while (j < s.length){
if (!/[0-9.]/.test(s[j])) break;
j++;
}
toks.push(s.slice(i, j)); i = j;
}
return toks;
}
function evalExpr(s){ return makeParser(tokenize(s)).parse(); }
var T = [];
function nz(rng, lo, hi){ var v = 0; while (v === 0) v = ri(rng, lo, hi); return v; }
/* easy: add integers */
T.push({id:'add', name:'Add integers', level:'easy', gen:function(rng){
var a = nz(rng, -9, 9), b = nz(rng, -9, 9);
var ans = a + b;
return {q:'Compute: ' + mhtml(sgn(a) + ' + ' + sgn(b)), a:String(ans), av:ans, alt:[],
data:{kind:'add', a:a, b:b},
hint:'Same sign: add and keep it. Different signs: subtract and keep the bigger one\'s sign.',
steps:['Signs: ' + (a < 0 === b < 0 ? 'same — add the magnitudes' : 'different — subtract the magnitudes') + '.',
'Answer: ' + ans + '']};
}});
/* easy: subtract integers */
T.push({id:'sub', name:'Subtract integers', level:'easy', gen:function(rng){
var a = nz(rng, -9, 9), b = nz(rng, -9, 9);
var ans = a - b;
var rw = b < 0 ? sgn(a) + ' + ' + (-b) : null;
return {q:'Compute: ' + mhtml(sgn(a) + ' − ' + sgn(b)), a:String(ans), av:ans, alt:[],
data:{kind:'sub', a:a, b:b},
hint:'Rewrite as adding the opposite: a − b = a + (−b).',
steps:[b < 0 ? 'Minus a negative: ' + mhtml(sgn(a) + ' − ' + sgn(b) + ' = ' + sgn(a) + ' + ' + (-b)) : 'Add the opposite: ' + mhtml(sgn(a) + ' + (' + (-b) + ')'),
'Answer: ' + ans + '']};
}});
/* easy: absolute value */
T.push({id:'abs', name:'Absolute value', level:'easy', gen:function(rng){
var x = nz(rng, -12, 12);
var ans = Math.abs(x);
return {q:'Compute: ' + mhtml('|' + x + '|'), a:String(ans), av:ans, alt:[],
data:{kind:'abs', x:x},
hint:'Absolute value is distance from zero — never negative.',
steps:['|' + x + '| is the distance from ' + x + ' to 0.',
'Answer: ' + ans + '']};
}});
/* medium: multiply integers */
T.push({id:'mul', name:'Multiply integers', level:'medium', gen:function(rng){
var a = nz(rng, -9, 9), b = nz(rng, -9, 9);
var ans = a * b;
return {q:'Compute: ' + mhtml(sgn(a) + ' × ' + sgn(b)), a:String(ans), av:ans, alt:[],
data:{kind:'mul', a:a, b:b},
hint:'Same signs → positive. Different signs → negative.',
steps:['Signs: ' + ((a < 0) === (b < 0) ? 'same → positive' : 'different → negative') + '.',
'Magnitudes: ' + Math.abs(a) + ' × ' + Math.abs(b) + ' = ' + Math.abs(ans) + '.',
'Answer: ' + ans + '']};
}});
/* medium: divide integers (exact) */
T.push({id:'div', name:'Divide integers', level:'medium', gen:function(rng){
var b = nz(rng, -9, 9);
if (b === 1 || b === -1) b = pick(rng, [2, -2, 3, -3]);
var q = nz(rng, -9, 9), a = b * q;
return {q:'Compute: ' + mhtml(sgn(a) + ' ÷ ' + sgn(b)), a:String(q), av:q, alt:[],
data:{kind:'div', a:a, b:b},
hint:'Same signs → positive. Different signs → negative. Then divide the magnitudes.',
steps:['Signs: ' + ((a < 0) === (b < 0) ? 'same → positive' : 'different → negative') + '.',
'Magnitudes: ' + Math.abs(a) + ' ÷ ' + Math.abs(b) + ' = ' + Math.abs(q) + '.',
'Answer: ' + q + '']};
}});
/* hard: order of operations with negatives */
var PATS = [
function(rng){ var a = nz(rng,-6,6), b = nz(rng,-6,6), c = nz(rng,-6,6);
return {e: a + '+' + b + '*' + c, d:'Multiply ' + sgn(b) + ' × ' + sgn(c) + ' first.'}; },
function(rng){ var a = nz(rng,-6,6), b = nz(rng,-6,6), c = nz(rng,-6,6);
return {e: '(' + a + '+' + b + ')*' + c, d:'Parentheses first: ' + sgn(a) + ' + ' + sgn(b) + '.'}; },
function(rng){ var a = nz(rng,-6,6), b = nz(rng,-6,6), c = nz(rng,-6,6), d = nz(rng,-6,6);
return {e: a + '-' + b + '*' + c + '+' + d, d:'Multiply before adding or subtracting.'}; },
function(rng){ var a = ri(rng, 2, 5);
return {e: '-(' + a + '^2)', d:'The exponent applies to ' + a + ' only, then the minus.'}; },
function(rng){ var a = ri(rng, 2, 5);
return {e: '(-' + a + ')^2', d:'Parentheses hand the exponent the whole (−' + a + ').'}; }
];
T.push({id:'ooo-neg', name:'Order of operations with negatives', level:'hard', gen:function(rng){
var p = pick(rng, PATS)(rng);
var ans = evalExpr(p.e);
var disp = p.e.replace(/\*/g, '×').replace(/\^/g, '^').replace(/-/g, '−');
return {q:'Evaluate: ' + mhtml(disp), a:String(ans), av:ans, alt:[],
data:{kind:'expr', expr:p.e},
hint:p.d,
steps:['Follow PEMDAS — exponents and ×/÷ before +/−.',
'Answer: ' + ans + '']};
}});
function checkAnswer(user, canonical, av){
var s = String(user).trim().replace(/,/g, '');
if (!/^-?(\d+(\.\d+)?|\.\d+)$/.test(s)) return false;
if (av === null || av === undefined) return false;
return Math.abs(parseFloat(s) - av) < 1e-9;
}
return {templates:T, checkAnswer:checkAnswer, evalExpr:evalExpr};
})();
// __QCORE_END__
/* Shared practice engine (Wave 2C). Requires QGEN global from the skill core. */ (function(){ 'use strict'; var correct = 0, streak = 0, total = 0, attempts = 0, cur = null, curT = null, lastIdx = -1; function $(id){ return document.getElementById(id); } function esc(s){ return String(s).replace(/\x26/g,'&').replace(//g,'>'); } function pickTemplate(){ var Ts = QGEN.templates, i, guard = 0; if (Ts.length === 1) return {t: Ts[0], i: 0}; i = Math.floor(Math.random() * Ts.length); for (guard = 0; guard < 11; guard++){ if (i !== lastIdx) break; i = Math.floor(Math.random() * Ts.length); } lastIdx = i; return {t: Ts[i], i: i}; } function newQuestion(){ var p = pickTemplate(); curT = p.t; cur = curT.gen(Math.random); attempts = 0; $('pType').textContent = curT.name; $('pPrompt').innerHTML = cur.q; $('pAnswer').value = ''; $('pAnswer').disabled = false; $('pCheck').disabled = false; hide($('pFb')); hide($('pHintBox')); hide($('pWhy')); $('pSol').style.display = 'none'; $('pNext').style.display = 'none'; updateStats(); $('pAnswer').focus(); } function show(el){ el.classList.add('show'); } function hide(el){ el.classList.remove('show'); } function updateStats(){ $('pStats').innerHTML = 'Correct ' + correct + ' of ' + total + '' + ' · Streak ' + streak + ''; } function feedback(ok, html){ var f = $('pFb'); f.className = 'fb show ' + (ok ? 'ok' : 'no'); f.innerHTML = html; } function check(){ if (!cur) return; var user = $('pAnswer').value; if (!user.trim()){ feedback(false, 'Enter an answer first.'); return; } var good = false; try { good = QGEN.checkAnswer(user, cur.a, cur.av); } catch(e){ good = false; } total++; if (good){ correct++; streak++; feedback(true, 'Correct. ' + esc(cur.a)); showSolution(false); $('pAnswer').disabled = true; $('pCheck').disabled = true; $('pNext').style.display = ''; $('pSol').style.display = 'none'; } else { streak = 0; attempts++; if (attempts >= 2){ feedback(false, 'Not quite. The answer is ' + esc(cur.a) + '. Study the steps below, then try the next one.'); showSolution(true); $('pAnswer').disabled = true; $('pCheck').disabled = true; $('pNext').style.display = ''; } else { feedback(false, 'Not quite — try again. Use the hint if you need it. The answer is ' + esc(cur.a) + ' only after a second miss.'); $('pSol').style.display = ''; } } updateStats(); } function showHint(){ if (!cur) return; var h = $('pHintBox'); h.innerHTML = 'Hint: ' + cur.hint; show(h); } function showSolution(force){ if (!cur) return; var w = $('pWhy'); var lis = cur.steps.map(function(s){ return '
'; }).join(''); w.innerHTML = '
- ' + lis + '
' + '
'; show(w); if (force){ $('pSol').style.display = 'none'; } } document.addEventListener('DOMContentLoaded', function(){ $('pCheck').addEventListener('click', check); $('pAnswer').addEventListener('keydown', function(e){ if (e.key === 'Enter') check(); }); $('pHint').addEventListener('click', showHint); $('pSol').addEventListener('click', function(){ showSolution(false); $('pSol').style.display='none'; }); $('pNext').addEventListener('click', newQuestion); $('pSkip').addEventListener('click', function(){ streak = 0; newQuestion(); }); newQuestion(); }); })();