Skill: percentages
Worksheet: Fraction–Decimal–Percent Conversions
Print a fresh 20-problem worksheet any time — Easy, Medium, or Hard, with a hidden answer key.
Generates 20 fresh problems on every click. The answer key stays hidden until you reveal it.
Fraction–Decimal–Percent Conversions
Answer Key
For the teacher or for self-checking after you finish.
// __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 gcd(a, b){ a = Math.abs(a); b = Math.abs(b); while (b){ var t = a % b; a = b; b = t; } return a || 1; }
function fnum(v, p){
var neg = v < 0, s = String(Math.abs(v));
while (s.length <= p) s = '0' + s;
var ip = s.slice(0, s.length - p), fp = s.slice(s.length - p).replace(/0+$/, '');
return (neg ? '-' : '') + (fp ? ip + '.' + fp : ip);
}
function mhtml(s){ return '' + s + ''; }
function parseNum(s){
s = String(s).trim().replace(/,/g, '').replace(/%$/, '');
var m = /^(-?\d+(?:\.\d+)?)\s*\/\s*(-?\d+(?:\.\d+)?)$/.exec(s);
if (m){ var d = parseFloat(m[2]); if (d === 0) return null; return parseFloat(m[1]) / d; }
if (!/^-?(\d+(\.\d+)?|\.\d+)$/.test(s)) return null;
return parseFloat(s);
}
var T = [];
/* easy: decimal -> percent */
T.push({id:'dec-pct', name:'Decimal to percent', level:'easy', gen:function(rng){
var p = ri(rng, 1, 3), v = ri(rng, 1, 999);
var dec = fnum(v, p), pct = v * Math.pow(10, 2 - p);
return {q:'Convert ' + mhtml(dec) + ' to a percent. (Enter just the number.)',
a:String(pct), av:pct, alt:[],
data:{kind:'d2p', v:v, p:p},
hint:'Multiply by 100: slide the point two places right.',
steps:['Percent means per hundred: multiply ' + dec + ' by 100.',
'Slide the point two places right: ' + pct + '%']};
}});
/* easy: percent -> decimal */
T.push({id:'pct-dec', name:'Percent to decimal', level:'easy', gen:function(rng){
var pdec = ri(rng, 0, 1);
var P = pdec === 0 ? ri(rng, 1, 99) : pick(rng, [5, 25, 75, 125, 375, 625]);
var dec = fnum(P, 2 + pdec);
return {q:'Convert ' + mhtml(P / Math.pow(10, pdec) + '%') + ' to a decimal.',
a:dec, av:P / Math.pow(10, 2 + pdec), alt:[],
data:{kind:'p2d', P:P, pdec:pdec},
hint:'Divide by 100: slide the point two places left.',
steps:['Divide by 100: slide the point two places left.',
'' + dec + '']};
}});
/* medium: fraction -> percent */
var FRACS = [[1,2],[1,4],[3,4],[1,5],[2,5],[3,5],[4,5],[1,8],[3,8],[5,8],[7,8],[1,10],[3,10],[7,10],[9,10],[1,20],[3,20],[7,20],[9,20]];
T.push({id:'frac-pct', name:'Fraction to percent', level:'medium', gen:function(rng){
var f = pick(rng, FRACS), n = f[0], d = f[1];
var pct = n / d * 100;
return {q:'Convert ' + mhtml(n + '/' + d) + ' to a percent. (Enter just the number.)',
a:String(pct), av:pct, alt:[],
data:{kind:'f2p', n:n, d:d},
hint:'Divide ' + n + ' ÷ ' + d + ' first, then slide the point two places right.',
steps:[mhtml(n + ' ÷ ' + d + ' = ' + (n / d)),
'Slide right two places: ' + pct + '%']};
}});
/* medium: percent -> simplified fraction */
T.push({id:'pct-frac', name:'Percent to fraction', level:'medium', gen:function(rng){
var p = pick(rng, [10, 20, 25, 30, 40, 45, 50, 60, 75, 80, 90]);
var g = gcd(p, 100);
var fn = p / g, fd = 100 / g;
return {q:'Write ' + mhtml(p + '%') + ' as a fraction in lowest terms. (Like 3/5.)',
a:fn + '/' + fd, av:p / 100, alt:[String(p / 100)],
data:{kind:'p2f', p:p},
hint:'Write it over 100, then divide top and bottom by their greatest common factor.',
steps:[mhtml(p + '% = ' + p + '/100'),
'Simplify (÷' + g + '): ' + fn + '/' + fd + '']};
}});
/* easy: benchmark percent of a number */
T.push({id:'bench', name:'Benchmark percents', level:'easy', gen:function(rng){
var b = pick(rng, [50, 25, 10, 1]);
var N = b === 50 ? 2 * ri(rng, 5, 60) : b === 25 ? 4 * ri(rng, 5, 40) : b === 10 ? 10 * ri(rng, 4, 40) : 100 * ri(rng, 1, 9);
var ans = b * N / 100;
var why = b === 50 ? 'half of ' + N : b === 25 ? 'a quarter of ' + N : b === 10 ? 'move the point one place left' : 'move the point two places left';
return {q:'Find ' + mhtml(b + '%') + ' of ' + mhtml(N) + ' mentally.',
a:String(ans), av:ans, alt:[],
data:{kind:'bench', b:b, N:N},
hint:'Use the benchmark: ' + why + '.',
steps:['Benchmark: ' + b + '% means ' + why + '.',
'' + ans + '']};
}});
/* medium: percent of a number */
T.push({id:'pct-of', name:'Percent of a number', level:'medium', gen:function(rng){
var p = pick(rng, [5, 10, 15, 20, 25, 30, 35, 40, 60, 75, 80, 90]);
var N = 20 * ri(rng, 2, 25);
var ans = p * N / 100;
return {q:'Find ' + mhtml(p + '%') + ' of ' + mhtml(N) + '.',
a:String(ans), av:ans, alt:[],
data:{kind:'pctof', p:p, N:N},
hint:'Convert ' + p + '% to ' + (p / 100) + ' first, then multiply.',
steps:[mhtml(p + '% = ' + (p / 100)),
mhtml((p / 100) + ' × ' + N + ' = ' + ans + '')]};
}});
/* hard: what percent? */
T.push({id:'what-pct', name:'What percent?', level:'hard', gen:function(rng){
var pct = pick(rng, [10, 20, 25, 30, 40, 50, 60, 75, 80]);
var whole = pick(rng, [40, 50, 60, 80, 100, 120, 160, 200]);
var part = pct * whole / 100;
return {q:'What percent of ' + mhtml(whole) + ' is ' + mhtml(part) + '? (Enter just the number.)',
a:String(pct), av:pct, alt:[],
data:{kind:'whatpct', part:part, whole:whole},
hint:'Divide part by whole, then convert the decimal to a percent.',
steps:[mhtml(part + ' ÷ ' + whole + ' = ' + (part / whole)),
'Convert to a percent: ' + pct + '%']};
}});
function checkAnswer(user, canonical, av){
var u = parseNum(user);
if (u === null || av === null || av === undefined) return false;
return Math.abs(u - av) < 1e-9;
}
return {templates:T, checkAnswer:checkAnswer, parseNum:parseNum};
})();
// __QCORE_END__
/* Shared worksheet engine (Wave 2C). Requires QGEN global. */ (function(){ 'use strict'; var COUNT = 20; function $(id){ return document.getElementById(id); } function esc(s){ return String(s).replace(/\x26/g,'&').replace(//g,'>'); } function templatesFor(level){ var Ts = QGEN.templates.filter(function(t){ return t.level === level; }); return Ts.length ? Ts : QGEN.templates.slice(); } function generate(){ var level = $('wLevel').value; var Ts = templatesFor(level); var probs = $('wProblems'), keyg = $('wKeyGrid'); probs.innerHTML = ''; keyg.innerHTML = ''; for (var i = 0; i < COUNT; i++){ var t = Ts[i % Ts.length]; var q = t.gen(Math.random); var d = document.createElement('div'); d.className = 'prob'; d.innerHTML = '' + (i + 1) + '' + q.q + ''; probs.appendChild(d); var k = document.createElement('div'); k.className = 'krow'; k.innerHTML = '' + (i + 1) + '' + esc(q.a) + ''; keyg.appendChild(k); } $('wKey').hidden = !$('wKeyToggle').getAttribute('aria-pressed') || $('wKeyToggle').getAttribute('aria-pressed') === 'false'; var lbl = {easy:'Easy', medium:'Medium', hard:'Hard'}[level] || level; $('wCount').textContent = COUNT + ' problems · ' + lbl; } document.addEventListener('DOMContentLoaded', function(){ $('wGen').addEventListener('click', generate); $('wPrint').addEventListener('click', function(){ window.print(); }); $('wKeyToggle').addEventListener('click', function(){ var on = this.getAttribute('aria-pressed') === 'true'; this.setAttribute('aria-pressed', String(!on)); this.textContent = on ? 'Show answer key' : 'Hide answer key'; $('wKey').hidden = on; }); generate(); }); })();