diff --git a/exercises/converting_fractions_to_decimals.html b/exercises/converting_fractions_to_decimals.html index 5f67aba13..b5636828a 100644 --- a/exercises/converting_fractions_to_decimals.html +++ b/exercises/converting_fractions_to_decimals.html @@ -12,9 +12,7 @@
randFromArray([4, 5, 8, 10, 20, 25, 50]) randRange(1, DENOMINATOR - 1) - Math.floor(NUMERATOR / DENOMINATOR * 1000) / 1000 roundTo(3, NUMERATOR / DENOMINATOR) - NUMERATOR * pow(10, 3)

Express the fraction as a decimal.

\dfrac{NUMERATOR}{DENOMINATOR}

@@ -22,17 +20,12 @@

This fraction represents the result of dividing NUMERATOR by DENOMINATOR.

-
- graph.divider = new Divider(DENOMINATOR, NUMERATOR_10, 0, 3); +
+ graph.divider = new Divider(DENOMINATOR, NUMERATOR, 0, 0, true); graph.divider.show(); - DUMMY = Array(graph.divider.getNumHints());
-
- graph.divider.shiftDecimals(); -
- -
+
graph.divider.showHint();
diff --git a/exercises/dividing_decimals_0.5.html b/exercises/dividing_decimals_0.5.html index 6dcc8aa04..d3a997f17 100644 --- a/exercises/dividing_decimals_0.5.html +++ b/exercises/dividing_decimals_0.5.html @@ -11,27 +11,20 @@
randFromArray([2, 5, 10]) - round( randRange(2, 9) * BOOST ) - roundTo( 1, randRange(2, 9) / BOOST ) - round( DIVISOR * QUOTIENT ) + round(randRange(2, 9) * BOOST) + roundTo(1, randRange(2, 9) / BOOST) + round(DIVISOR * QUOTIENT)

Please give your answer in decimal form.

- graph.divider = new Divider( DIVISOR, DIVIDEND ); + graph.divider = new Divider(DIVISOR, DIVIDEND, 0, 0, true); graph.divider.show(); - DUMMY1 = Array(graph.divider.getNumHints()); - DUMMY2 = Array(3); + DUMMY = Array(graph.divider.getNumHints());
QUOTIENT
-
- graph.divider.showHint(); -
-
- graph.divider.addDecimalRemainder(); -
-
+
graph.divider.showHint();
diff --git a/exercises/dividing_decimals_3.html b/exercises/dividing_decimals_3.html index daba480b8..672a6bb79 100644 --- a/exercises/dividing_decimals_3.html +++ b/exercises/dividing_decimals_3.html @@ -7,7 +7,7 @@
-
+
randRange(11, 99) randRange(5, 99) DIVISOR * QUOTIENT diff --git a/exercises/dividing_decimals_4.html b/exercises/dividing_decimals_4.html index 511d03148..38d16d2ee 100644 --- a/exercises/dividing_decimals_4.html +++ b/exercises/dividing_decimals_4.html @@ -7,7 +7,7 @@
-
+
randRange( 10, 99 ) randRange( 100, 999 ) DIVISOR * QUOTIENT diff --git a/exercises/division_1.5.html b/exercises/division_1.5.html index 46d7cea8d..bb63fb588 100644 --- a/exercises/division_1.5.html +++ b/exercises/division_1.5.html @@ -8,8 +8,9 @@
- randRange( 2, 9 ) - randRange(10, 99) + randRange(2, 9) + rand(2) ? randRange(20, 99) : randRange(100, 999) + floor(PRE_DIVIDEND / DIVISOR) DIVISOR * QUOTIENT []
diff --git a/exercises/division_2.html b/exercises/division_2.html index 253a5c705..c35c7455e 100644 --- a/exercises/division_2.html +++ b/exercises/division_2.html @@ -8,13 +8,14 @@
- randRange( 2, 9 ) - randRange( 10, 999 ) - randRange( 1, DIVISOR - 1 ) - DIVISOR * QUOTIENT + FINAL_REMAINDER - integerToDigits( DIVIDEND ) + randRange(2, 9) + rand(2) ? randRange(100, 999) : randRange(1000, 9999) + floor(PRE_DIVIDEND / DIVISOR) + randRange(1, DIVISOR - 1) + DIVISOR * QUOTIENT + REMAINDER []
+
@@ -25,20 +26,17 @@
QUOTIENT\text{ R } - FINAL_REMAINDER + REMAINDER
Write your answer as a whole number and remainder.

a quotient and remainder, like 5 \text{ R } 3

-
-
-
-
- graph.divider.showHint(); -
-
- drawDigits( [ "\\text{R}" ].concat( integerToDigits( FINAL_REMAINDER ) ), DIVIDEND_DIGITS.length, 1 ); +
+
+ graph.divider.showHint(); +
+
diff --git a/exercises/division_3.html b/exercises/division_3.html index 02f1cde04..04680ba4c 100644 --- a/exercises/division_3.html +++ b/exercises/division_3.html @@ -7,9 +7,10 @@
-
+
randRange(10, 99) - randRange(ceil(100 / DIVISOR), floor(9999 / DIVISOR)) + rand(2) ? randRange(100, 999) : randRange(1000, 9999) + floor(PRE_DIVIDEND / DIVISOR) DIVISOR * QUOTIENT []
diff --git a/exercises/division_4.html b/exercises/division_4.html index a67c56d29..c24654d67 100644 --- a/exercises/division_4.html +++ b/exercises/division_4.html @@ -7,12 +7,12 @@
-
- randRange( 10, 99 ) - randRange(ceil(100 / DIVISOR), floor(9999 / DIVISOR)) - randRange( 1, DIVISOR - 1 ) - DIVISOR * QUOTIENT + FINAL_REMAINDER - integerToDigits( DIVIDEND ) +
+ rand(2) ? randRange(10, 99) : randRange(100, 999) + rand(2) ? randRange(100, 999) : randRange(1000, 9999) + floor(PRE_DIVIDEND / DIVISOR) + randRange(1, DIVISOR - 1) + DIVISOR * QUOTIENT + REMAINDER
@@ -24,7 +24,7 @@
QUOTIENT\text{ R } - FINAL_REMAINDER + REMAINDER
Write your answer as a whole number and remainder.

a quotient and remainder, like 5 \text{ R } 3

@@ -35,10 +35,6 @@
graph.divider.showHint();
- -
- drawDigits( [ "\\text{R}" ].concat( integerToDigits( FINAL_REMAINDER ) ), DIVIDEND_DIGITS.length, 1 ); -
diff --git a/exercises/division_test.html b/exercises/division_test.html new file mode 100644 index 000000000..34ee52173 --- /dev/null +++ b/exercises/division_test.html @@ -0,0 +1,220 @@ + + + + + Division test + + + +
+
+ 0 + 0 + 0 +
+ +
+
+
+ 4 + 48 +
+
+ +
+
+ 24 + 4800 +
+
+ +
+
+ 10 + 1000 +
+
+ +
+
+ 4 + 408 +
+
+ +
+
+ 24 + 312 +
+
+ +
+
+ 18 + 1458 +
+
+ +
+
+ 18 + 1962 +
+
+ +
+
+ 4 + 50 +
+
+ +
+
+ 4 + 1922 +
+
+ +
+
+ 80 + 6928 +
+
+ +
+
+ 4 + 48 + 1 + 1 +
+
+ +
+
+ 13 + 858 + 2 + 1 +
+
+ +
+
+ 62 + 21452 + 2 + 3 +
+
+ +
+
+ 2 + 246 + 0 + 1 +
+
+ +
+
+ 5 + 18 + 2 + 0 +
+
+ +
+
+ 70 + 49 + 1 +
+
+ +
+
+ 8 + 3 + true +
+
+ +
+
+ 25 + 24 + true +
+
+ +
+
+ 3 + 10 + true +
+
+ +
+
+ 4 + 480 + 0 + 1 + true +
+
+ +
+
+ 4 + 48 + 0 + 3 + true +
+
+ +
+
+ 24 + 48 + 2 + true +
+
+ +
+
+ 4 + 480 + 0 + 3 + true +
+
+
+ +
+
+ graph.divider = new Divider(DIVISOR, DIVIDEND, DIVISOR_DECIMAL, DIVIDEND_DECIMAL, DECIMAL_REMAINDER); + graph.divider.show(); + DUMMY = Array(graph.divider.getNumHints()); +
+
+
1
+ +
+
+ graph.divider.showHint(); +
+
+
+ + diff --git a/utils/graphie-helpers-arithmetic.js b/utils/graphie-helpers-arithmetic.js index 41a139d0c..c719da3f8 100644 --- a/utils/graphie-helpers-arithmetic.js +++ b/utils/graphie-helpers-arithmetic.js @@ -557,47 +557,50 @@ function Multiplier(a, b, digitsA, digitsB, deciA, deciB) { }; } -function Divider(divisor, dividend, deciDivisor, deciDividend) { +function Divider(divisor, dividend, deciDivisor, deciDividend, decimalRemainder) { var graph = KhanUtil.currentGraph; var digitsDivisor = KhanUtil.integerToDigits(divisor); var digitsDividend = KhanUtil.integerToDigits(dividend); deciDivisor = deciDivisor || 0; deciDividend = deciDividend || 0; + + deciDividend = Divider.processDividend(digitsDividend, deciDividend); var deciDiff = deciDivisor - deciDividend; + var hints = Divider.getHints(divisor, digitsDividend, deciDivisor, deciDividend, decimalRemainder); + var numHints = hints.length; + var highlights = []; + var leadingZeros = []; + var decimals = []; + var temporaryLabel = false; var index = 0; + var dx = 0; var dy = 0; - var remainder = 0; + var currentValue = 0; var fOnlyZeros = true; - var leadingZeros = []; - var value = 0; - var decimals = []; - - var hints = 0; - var hintType = 1; - var numHints = Divider.numHintsFor(divisor, dividend, deciDivisor, deciDividend); - - if (deciDividend !== 0) { - digitsDividend = (KhanUtil.padDigitsToNum(digitsDividend.reverse(), deciDividend + 1)).reverse(); - } this.show = function() { - var paddedDivisor = digitsDivisor; - var nDigitsInAnswer = Math.floor(Math.log(dividend / divisor) / Math.log(10)) + 1; - var answerAsDigits = KhanUtil.integerToDigits(Math.round(dividend / divisor)); - - // Since we stop dividing once we get a remainder of 0 - var i = answerAsDigits.length - 1; - while (answerAsDigits[i] === 0) { - nDigitsInAnswer--; - i--; + // Count number of subdivisions shown and find how many decimals have been added + var steps = 0; + var decimalsAdded = 0; + for (var i = 0; i < hints.length; i++) { + if (hints[i][0] === 'result' && hints[i][1] !== 0) { + steps++; + } else if (hints[i][0] === 'decimal-remainder') { + decimalsAdded = hints[i][1]; + } } + // Calculate the x-coordinate for the hints + dx = digitsDividend.length + decimalsAdded + Math.max(0, deciDiff) + 0.5; + + var paddedDivisor = digitsDivisor; if (deciDivisor !== 0) { paddedDivisor = (KhanUtil.padDigitsToNum(digitsDivisor.reverse(), deciDivisor + 1)).reverse(); } + graph.init({ - range: [[-1 - paddedDivisor.length, 17], [-2 * nDigitsInAnswer - 3, 2]], + range: [[-1 - paddedDivisor.length, 17], [-2 * steps - 1, 2]], scale: [20, 40] }); @@ -615,223 +618,302 @@ function Divider(divisor, dividend, deciDivisor, deciDividend) { [digitsDividend.length - deciDividend - 0.5, -0.1], "\\LARGE{" + decimalPointSymbol + "}", "center", true)); } - if (deciDiff !== 0) { - decimals = decimals.concat( - graph.label( - [digitsDividend.length - deciDividend - 0.5, 0.9], - "\\LARGE{" + decimalPointSymbol + "}", "center", true)); - } }); drawDigits(paddedDivisor, -0.5 - paddedDivisor.length, 0); drawDigits(digitsDividend, 0, 0); - graph.path([[-0.75, -0.5], [-0.75, 0.5], [digitsDividend.length + (deciDiff > 0 ? deciDiff : 0), 0.5]]); + graph.path([[-0.75, -0.5], [-0.75, 0.5], [dx - 0.8, 0.5]]); }; this.showHint = function() { - this.removeHighlights(); - hints++; + this.clearArray(highlights); + var hint = hints.shift(); - if (hints === 1 && deciDivisor > 0) { - this.shiftDecimals(); - return; + // For the last hint, remove leading zero in the answer + if (hints.length === 0) { + this.clearArray(leadingZeros); } - // End of hints - if (hints === numHints || index === digitsDividend.length) { - while (leadingZeros.length) { - leadingZeros.pop().remove(); - } - - if (remainder === 0) { - graph.label([digitsDividend.length + 0.5, dy], "\\text{" + - $._("The remainder is 0 so we have our answer.") + "}", "right"); - } - return; + switch (hint[0]) { + case 'shift': + this.shiftDecimals(); + break; + case 'bring-up-decimal': + this.bringUpDecimal(); + break; + case 'division': + currentValue = hint[1]; + this.showDivisionStep(); + break; + case 'result': + this.showDivisionStepResult(hint[1], hint[2], hint[3]); + break; + case 'decimal-remainder': + this.addDecimalRemainder(); + break; + case 'remainder': + this.showRemainder(hint[1]); + break; } + }; - if (hintType === 1) { - hintType = 0; - value = digitsDividend[index]; - var quotient = value / divisor; - var total = value + remainder; - highlights = highlights.concat(drawDigits([value], index, 0, KhanUtil.BLUE)); + this.shiftDecimals = function() { + this.clearArray(decimals); - if (!fOnlyZeros) { - graph.style({ - arrows: "->" - }, function() { - highlights.push(graph.path([[index, -0.5], [index, dy + 0.5]])); - }); - } + temporaryLabel = graph.label([dx, 1], + $.ngettext("\\text{Shift the decimal 1 to the right.}", + "\\text{Shift the decimal %(num)s to the right.}", + deciDivisor), + "right"); - var totalDigits = KhanUtil.integerToDigits(total); - highlights = highlights.concat(drawDigits(totalDigits, index - totalDigits.length + 1, dy, KhanUtil.BLUE)); + this.addDecimals([[-1, -0.1], [digitsDividend.length + deciDiff - 0.5, -0.1]]); - var question = $._("\\text{How many times does }%(divisor)s" + - " \\text{ go into }\\color{#6495ED}{%(total)s}\\text{?}", - {divisor: divisor, total: total}); + // Draw extra zeros in the dividend + if (deciDiff > 0) { + var orig = digitsDividend; + digitsDividend = KhanUtil.padDigitsToNum(digitsDividend, digitsDividend.length + deciDiff); + var x = digitsDividend.length - deciDiff; + var zeros = digitsDividend.slice(x); + drawDigits(zeros, x, 0); + highlights = highlights.concat(drawDigits(zeros, x, 0, KhanUtil.PINK)); + } + }; - if (total >= divisor) { - graph.label([digitsDividend.length + 0.5, dy], question, "right"); - } else { - highlights = highlights.concat(graph.label([digitsDividend.length + 0.5, dy], question, "right")); - } + this.bringUpDecimal = function() { + if (temporaryLabel) { + temporaryLabel.remove(); + temporaryLabel = false; + } + + // TODO(jeresig): i18n: This probably won't work in multiple langs + graph.label([dx, 1.2], $._("\\text{Bring the decimal up into the}"), "right"); + graph.label([dx, 0.8], $._("\\text{answer (the quotient).}"), "right"); + this.addDecimals([[digitsDividend.length + deciDiff - 0.5, 0.9]]); + } + this.showDivisionStep = function(division) { + // Write question + var question = $._("\\text{How many times does }%(divisor)s" + + "\\text{ go into }\\color{#6495ED}{%(value)s}\\text{?}", + {divisor: divisor, value: currentValue}); + + if (currentValue >= divisor) { + graph.label([dx, dy], question, "right"); } else { - hintType = 1; - - value += remainder; - var quotient = Math.floor(value / divisor); - var diff = value - (quotient * divisor); - remainder = diff * 10; - - var quotientLabel = drawDigits([quotient], index, 1); - highlights = highlights.concat(drawDigits([quotient], index, 1, KhanUtil.GREEN)); - - // If quotient is 0 then don't show the division - if (quotient === 0) { - index++; - if (fOnlyZeros) { - if (digitsDividend.length - deciDividend + deciDivisor > index) { - leadingZeros = leadingZeros.concat(quotientLabel); - } - } - return; - } + highlights = highlights.concat(graph.label([dx, dy], question, "right")); + } - var digits = KhanUtil.integerToDigits(value); - if (fOnlyZeros) { - drawDigits(digits, index - digits.length + 1, dy); - fOnlyZeros = false; - } else { + // Bring down another number + if (!fOnlyZeros) { + graph.style({ + arrows: "->" + }, function() { + highlights.push(graph.path([[index, -0.5], [index, dy + 0.5]])); + }); + + if (digitsDividend[index]) { drawDigits([digitsDividend[index]], index, dy); + } else { + // Add a zero in the dividend and bring that down + drawDigits([0], index, 0); + drawDigits([0], index, dy); } + } - var product = KhanUtil.integerToDigits(divisor * quotient); - drawDigits(product, index - product.length + 1, dy - 1); - highlights = highlights.concat(drawDigits(product, index - product.length + 1, dy - 1, KhanUtil.ORANGE)); - - var diffDigits = KhanUtil.integerToDigits(diff); - drawDigits(diffDigits, index - diffDigits.length + 1, dy - 2); - graph.path([[index - product.length - 0.25, dy - 1.5], [index + 0.5, dy - 1.5]]); - graph.label([index - digits.length, dy - 1] , "-"); - - graph.label([digitsDividend.length + 0.5, dy - 1], - "\\color{#6495ED}{" + value + "}" + - "\\div" + - divisor + "=" + - "\\color{#28AE7B}{" + quotient + "}" + - "\\text{ " + $._("or") + " }" + - divisor + - "\\times" + - "\\color{#28AE7B}{" + quotient + "}" + - " = " + - "\\color{#FFA500}{" + (divisor * quotient) + "}", "right"); - index++; + // Highlight current dividend + var digits = KhanUtil.integerToDigits(currentValue); + highlights = highlights.concat(drawDigits(digits, index - digits.length + 1, dy, KhanUtil.BLUE)); + }; + + this.showDivisionStepResult = function(result, remainder) { + if (result !== 0) { + fOnlyZeros = false; + } + + // Leading zeros except one before a decimal point and those after + // are stored separately so they can be removed later. + if (fOnlyZeros && index < digitsDividend.length + deciDiff - 1) { + leadingZeros = leadingZeros.concat(drawDigits([0], index, 1)); + } else { + drawDigits([result], index, 1); + } + + // Highlight result + highlights = highlights.concat(drawDigits([result], index, 1, KhanUtil.GREEN)); + + if (result !== 0) { dy -= 2; + var productDigits = KhanUtil.integerToDigits(result * divisor); + var productLength = productDigits.length; + drawDigits(productDigits, index - productLength + 1, dy + 1); + + graph.path([[index - productLength - 0.25, dy + 0.5], [index + 0.5, dy + 0.5]]); + graph.label([index - productLength, dy + 1] , "-"); + + var remainderDigits = KhanUtil.integerToDigits(remainder); + var remainderX = index - remainderDigits.length + 1; + drawDigits(remainderDigits, remainderX, dy); + highlights = highlights.concat(drawDigits(remainderDigits, remainderX, dy, KhanUtil.PINK)); + + graph.label([dx, dy + 1], + "\\blue{" + currentValue + "}" + + "\\div" + divisor + "=" + + "\\green{" + result + "}" + + "\\text{" + $._(" with a remainder of ") + " }" + + "\\pink{" + remainder + "}", + "right"); } - }; + + index++; + } this.addDecimalRemainder = function() { - dividend = dividend * 10; - digitsDividend = KhanUtil.integerToDigits(dividend); + digitsDividend = KhanUtil.integerToDigits(dividend * 10); deciDividend = 1; deciDiff = deciDivisor - deciDividend; - this.addDecimal(); - this.show(); - graph.label([digitsDividend.length, 1], - $._("\\text{Write in a decimal and a zero and continue dividing.}"), - "right"); + drawDigits([0], index, 0); + this.addDecimals([[index - 0.5, 0.9], [index - 0.5, -0.1]]); + + graph.label([dx, 1], $._("\\text{Write in a decimal and a zero.}"), "right"); }; + this.showRemainder = function(remainder) { + var txt; + if (remainder === 0) { + txt = "\\text{" + $._("The remainder is 0 so we have our answer.") + "}"; + } else { + txt = $._("\\text{Since } %(remainder)s \\text{ is less than } %(divisor)s \\text{, it is left as our remainder.}", + { remainder: remainder, divisor: divisor }); + + drawDigits(["\\text{R}"].concat(KhanUtil.integerToDigits(remainder)), digitsDividend.length, 1); + } + + graph.label([dx, dy], txt, "right"); + } + this.getNumHints = function() { return numHints; }; - this.removeHighlights = function() { - while (highlights.length) { - highlights.pop().remove(); + this.clearArray = function(arr) { + while (arr.length) { + arr.pop().remove(); } }; - this.addDecimal = function() { + this.addDecimals = function(coords) { graph.style({ fill: "#000" }, function() { - graph.label([digitsDividend.length + deciDiff - 0.5, -0.1], - "\\LARGE{" + decimalPointSymbol + "}", "center", true); - graph.label([digitsDividend.length + deciDiff - 0.5, 0.9], - "\\LARGE{" + decimalPointSymbol + "}", "center", true); + for (var i = 0; i < coords.length; i++) { + graph.label(coords[i], "\\LARGE{" + decimalPointSymbol + "}", "center", true); + } }); }; - this.shiftDecimals = function() { - while (decimals.length) { - decimals.pop().remove(); - } - - if (deciDivisor !== 0) { - graph.label([digitsDividend.length + 1 + (deciDiff > 0 ? deciDiff : 0), 1], - $.ngettext("\\text{Shift the decimal 1 to the right.}", - "\\text{Shift the decimal %(num)s to the right.}", - deciDivisor), - "right"); - graph.style({ - fill: "#000" - }, function() { - graph.label([-1, -0.1], - "\\LARGE{" + decimalPointSymbol + "}", "center", true); - }); - } else { - // TODO(jeresig): i18n: This probably won't work in multiple langs - graph.label([digitsDividend.length + 0.5, 1.2], - $._("\\text{Bring the decimal up into the}"), "right"); - graph.label([digitsDividend.length + 0.5, 0.8], - $._("\\text{answer (the quotient).}"), "right"); - } +} - this.addDecimal(); +// Go through the division step-by-step +// Return steps as an array of arrays, +// where the first item is the type of hint and following items are parameters. +// The hint types are: +// ['shift'] The divisor is a decimal, so shift the decimal to make it an integer. +// ['bring-up-decimal'] The dividend is a decimal, so bring up decimal point into the quotient. +// ['decimal-remainder', param1] decimalRemainder is true and we need to add decimals to the dividend to continue. +// Param1 is the number of zeros added (to a maximum of 4). +// e.g. for 1 / 8, we add a decimal and 3 zeros so 1 becomes 1.000. +// ['division', param1] Show a sub-division step, dividing param1 by the divisor. +// e.g. For 58 / 2, the first step is to divide 5 (param1) by 2. +// ['result', param1, param2] Show the result of a sub-division step. The result is param1 remainder param2. +// e.g. For 5 / 2, param1 is 2 and param2 is 1. +// ['remainder', param1] Show the remainder of param1 (Usually 0 showing we have finished). +// Appended to the end of the hints is the number of decimals added as part of the decimal-remainder step + +Divider.getHints = function(divisor, digitsDividend, deciDivisor, deciDividend, decimalRemainder) { + var hints = []; + //var digitsDividend = KhanUtil.integerToDigits(dividend); + var dividend = 0; - if (deciDiff > 0) { - var orig = digitsDividend; - digitsDividend = KhanUtil.padDigitsToNum(digitsDividend, digitsDividend.length + deciDiff); - drawDigits(digitsDividend, 0, 0); - highlights = highlights.concat(drawDigits(digitsDividend, 0, 0, KhanUtil.PINK)); - highlights = highlights.concat(drawDigits(orig, 0, 0)); + if (deciDivisor > 0) { + hints.push(['shift']); + if (deciDivisor > deciDividend) { + digitsDividend = KhanUtil.padDigitsToNum(digitsDividend, digitsDividend.length + deciDivisor - deciDividend); } - }; -} - -Divider.numHintsFor = function(divisor, dividend, deciDivisor, deciDividend) { - var digitsDividend = KhanUtil.integerToDigits(dividend); - if (deciDividend !== 0) { - digitsDividend = (KhanUtil.padDigitsToNum(digitsDividend.reverse(), deciDividend + 1)).reverse(); } - var numhints = 1 + (digitsDividend.length + Math.max(deciDivisor - deciDividend, 0)) * 2; - var remainingDecimals = Math.max(deciDividend - deciDivisor, 0); - if (deciDivisor > 0) { - numhints++; + if (deciDividend > deciDivisor) { + hints.push(['bring-up-decimal']); } - // If answer ends in zeros that we don't use - if (Math.round(dividend / divisor) === dividend / divisor) { - var digitsAnswer = KhanUtil.integerToDigits(dividend / divisor); + // If we want a decimal remainder, add up to 4 extra places + var numPlaces = digitsDividend.length + (decimalRemainder ? 4 : 0); + var digits = KhanUtil.padDigitsToNum(digitsDividend, numPlaces); + var decimalsAdded = 0; + var decimalsRemainder = ['decimal-remainder', 0]; - for (var i = 0; i < remainingDecimals; i++) { - if (digitsAnswer[digitsAnswer.length - 1 - i] === 0) { - numhints -= 2; - } else { + for (var i = 0; i < digits.length; i++) { + if (i >= digitsDividend.length) { + if (dividend === 0) { + // No need to add more decimals break; + } else { + decimalsAdded++; } + + if (i === digitsDividend.length) { + hints.push(decimalsRemainder); + } + } + + if (decimalsAdded > 0) { + decimalsRemainder[1] = decimalsAdded; } + + dividend = dividend * 10 + digits[i]; + hints.push(['division', dividend]); + + var quotient = Math.floor(dividend / divisor); + var product = divisor * quotient; + dividend -= product; + hints.push(['result', quotient, dividend]); + } + + if (dividend === 0 || decimalsAdded !== 4) { + hints.push(['remainder', dividend]); } - return numhints; + return hints; }; +Divider.getNumberOfHints = function(divisor, dividend, deciDivisor, deciDividend, decimalRemainder) { + var digitsDividend = KhanUtil.integerToDigits(dividend); + deciDividend = Divider.processDividend(digitsDividend, deciDividend); + var hints = Divider.getHints(divisor, digitsDividend, deciDivisor, deciDividend, decimalRemainder); + return hints.length; +} + +Divider.processDividend = function(dividendDigits, deciDividend) { + // Trim unnecessary zeros after the decimal point + var end = dividendDigits.length - 1; + for (var i = 0; i < deciDividend; i++) { + if (dividendDigits[end - i] === 0) { + dividendDigits.splice(end - i) + deciDividend--; + } else { + break; + } + } + + // Add zeros before the decimal point + var extraZeros = deciDividend - dividendDigits.length + 1; + for (var i = 0; i < extraZeros; i++) { + dividendDigits.splice(0, 0, 0); + } + + return deciDividend; +} + KhanUtil.Adder = Adder; KhanUtil.Subtractor = Subtractor; KhanUtil.Multiplier = Multiplier;