# Khan/khan-exercises

### Subversion checkout URL

You can clone with
or
.

Summary:
concave_up_and_concave_down_intervals.html
positive_and_negative_intervals.html
positive_and_negative_slope_intervals_1.html
positive_and_negative_slope_intervals_2.html

Test Plan: Tested locally

Reviewers: alpert, stephanie

Reviewed By: stephanie

Differential Revision: http://phabricator.khanacademy.org/D1
1 parent d029dd7 commit 059776bfd592419a061ba00802fd38c1c9c056d0 beneater committed
240 exercises/positive_and_negative_parts_of_functions.html
 @@ -0,0 +1,240 @@ + + + + + Positive and negative parts of functions + + + + +
+
+ + randFromArray([ + [[ 1, 0, -16, 0, 49], [-5, 5], [-100, 100]], + [[-1, 0, 16, 0, -49], [-5, 5], [-250, 100]], + [[ 1, 3, -14, -35, 21], [-5, 5], [-100, 200]], + [[-1, -3, 14, 35, 0], [-5, 5], [-200, 100]], + [[ 1, 4, -1, -4], [-5, 5], [ -40, 120]], + [[ -1, -4, 1, 4], [-5, 5], [-150, 40]], + [[ 1, 0, -16, 0], [-5, 5], [ -50, 50]], + [[ -1, 0, 16, 0], [-5, 5], [ -70, 60]], + [[ 1, 0, -22, 27], [-5, 5], [ -30, 70]], + [[ -1, 0, 22, -27], [-5, 5], [ -70, 30]], + [[ 1, 1, -13, -14], [-5, 5], [ -40, 40]], + [[ -1, -1, 13, 14], [-5, 5], [ -40, 40]], + [[ 1, 0, -12], [-5, 5], [ -20, 20]], + [[ -1, 0, 12], [-5, 5], [ -20, 20]], + [[ 1, -1, -6], [-5, 5], [ -20, 20]], + [[ -1, 1, 6], [-5, 5], [ -30, 20]], + [[ 1, 0, -3], [-5, 5], [ -20, 30]], + [[ -1, 0, 3], [-5, 5], [ -30, 20]], + [[ 1, 2, 0], [-5, 5], [ -10, 35]], + [[ -1, -2, 0], [-5, 5], [ -40, 20]] + ]) + new Polynomial(0, COEF.length - 1, COEF.reverse()) + + function(x) {return POLYNOMIAL.evalOf(x);} + + + _.reduce(findRootsNumerically(FNX, XRANGE), function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, [XRANGE]) + + _.filter(FNX_INTERVALS, function(intv) { + return FNX(intv[0] + (intv[1] - intv[0]) / 2) > 0; + }) + + + _.sortBy(FNX_INTERVALS_POS, function(intv) { + return intv[0] - intv[1]; + })[0] + + + _.filter(FNX_INTERVALS, function(intv) { + return FNX(intv[0] + (intv[1] - intv[0]) / 2) < 0; + }) + + + _.sortBy(FNX_INTERVALS_NEG, function(intv) { + return intv[0] - intv[1]; + })[0] + +
+ +
+
+ Move the blue window to select part of the function. +
+
+ graph.slidingWindow.getX() +
+
+ var correct = _.reduce(_.range(guess, guess + 1, 0.02), function(correct, x) { + return correct && PREDICATE(x); + }, true); + if (!graph.moved && !correct) { + return "" + } + return correct; +
+
+ graph.slidingWindow.moveTo(guess, 0); +
+
+ +

+

+ +
+
+ initAutoscaledGraph([XRANGE, YRANGE]); + addMouseLayer(); + plot(FNX, XRANGE, { + stroke: BLUE, + strokeWidth: 3 + }); + graph.moved = false; + // start the selection at the first zero of f(x) which is + // guaranteed to be wrong but not give info about the right answer + var startX = FNX_INTERVALS[0][1] - 0.5; + graph.slidingWindow = KhanUtil.addRectGraph({ + x: startX, + y: YRANGE[0], + width: 1, + height: YRANGE[1] - YRANGE[0], + normalStyle: { + area: { "fill-opacity": 0.2 }, + edges: { "stroke-width": 0 } + }, + hoverStyle: { + area: { "fill-opacity": 0.3 } + }, + fixed: { + points: [true, true, true, true], + edges: [true, true, true, true] + }, + constraints: { + constrainX: false, + constrainY: true, + xmin: XRANGE[0], + xmax: XRANGE[1] + }, + onMove: function() { + graph.moved = true; + } + }); +
+

+ f(x) = POLYNOMIAL.text() +

+
+ +
+
+
+ function(x) { return FNX(x) > 0; } +
+ +

+ A function f(x) is plotted below. + Highlight an interval where f(x) > 0. +

+ +
+

+ The function f(x) is greater than 0 + wherever it's positive. +

+
+

+ The plural("interval", FNX_INTERVALS_POS.length) + where f(x) is positive + plural("is", FNX_INTERVALS_POS.length) + highlighted above. +

+
+ plot(FNX, [XRANGE[0] - 1, XRANGE[1] + 1], { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }).attr("clip-rect", + scalePoint([range[0][0], range[1][1]])[0] + "," + + scalePoint([range[0][0], range[1][1]])[1] + "," + + scaleVector([range[0][1] - range[0][0], range[1][1]])[0] + "," + + scaleVector([range[0][1] - range[0][0], range[1][1]])[1] + ); +
+
+
+

+ Select any part of the function that's highlighted. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL_POS[1] - SOLUTION_INTERVAL_POS[0]) / 2 + + SOLUTION_INTERVAL_POS[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return FNX(x) < 0; } +
+ +

+ A function f(x) is plotted below. + Highlight an interval where f(x) < 0. +

+ +
+

+ The function f(x) is less than 0 + wherever it's negative. +

+
+

+ The plural("interval", FNX_INTERVALS_NEG.length) + where f(x) is negative + plural("is", FNX_INTERVALS_NEG.length) + highlighted above. +

+
+ plot(FNX, [XRANGE[0] - 1, XRANGE[1] + 1], { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }).attr("clip-rect", + scalePoint([range[0][0], 0])[0] + "," + + scalePoint([range[0][0], 0])[1] + "," + + scaleVector([range[0][1] - range[0][0], -range[1][0]])[0] + "," + + scaleVector([range[0][1] - range[0][0], -range[1][0]])[1] + ); +
+
+
+

+ Select any part of the function that's highlighted. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL_NEG[1] - SOLUTION_INTERVAL_NEG[0]) / 2 + + SOLUTION_INTERVAL_NEG[0] - 0.5, 0); +
+
+
+
+ +
+
+ +
432 exercises/recognizing_concavity.html
 @@ -0,0 +1,432 @@ + + + + + Recognizing concativity + + + + +
+
+ + randFromArray([ + [[ 1, 0, -16, 0, 49], [-5, 5], [-100, 100]], + [[-1, 0, 16, 0, -49], [-5, 5], [-250, 100]], + [[ 1, 3, -14, -35, 21], [-5, 5], [-100, 200]], + [[-1, -3, 14, 35, 0], [-5, 5], [-200, 100]], + [[ 1, 4, -1, -4], [-5, 5], [ -40, 120]], + [[ -1, -4, 1, 4], [-5, 5], [-150, 40]], + [[ 1, 0, -16, 0], [-5, 5], [ -50, 50]], + [[ -1, 0, 16, 0], [-5, 5], [ -70, 60]], + [[ 1, 0, -22, 27], [-5, 5], [ -30, 70]], + [[ -1, 0, 22, -27], [-5, 5], [ -70, 30]], + [[ 1, 1, -13, -14], [-5, 5], [ -40, 40]], + [[ -1, -1, 13, 14], [-5, 5], [ -40, 40]], + [[ 1, 0, -12], [-5, 5], [ -20, 20]], + [[ -1, 0, 12], [-5, 5], [ -20, 20]], + [[ 1, -1, -6], [-5, 5], [ -20, 20]], + [[ -1, 1, 6], [-5, 5], [ -30, 20]], + [[ 1, 0, -3], [-5, 5], [ -20, 30]], + [[ -1, 0, 3], [-5, 5], [ -30, 20]], + [[ 1, 2, 0], [-5, 5], [ -10, 35]], + [[ -1, -2, 0], [-5, 5], [ -40, 20]] + ]) + new Polynomial(0, COEF.length - 1, COEF.reverse()) + + function(x) {return POLYNOMIAL.evalOf(x);} + function(x) {return POLYNOMIAL.derivative().evalOf(x);} + function(x) {return POLYNOMIAL.derivative().derivative().evalOf(x);} + + + _.reduce(findRootsNumerically(DDX, XRANGE), function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, [XRANGE]) + + _.reduce(findRootsNumerically(D2DX, XRANGE), function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, [XRANGE]) + + _.filter(DDX_INTERVALS, function(intv) { + return DDX(intv[0] + (intv[1] - intv[0]) / 2) > 0; + }) + + _.filter(DDX_INTERVALS, function(intv) { + return DDX(intv[0] + (intv[1] - intv[0]) / 2) < 0; + }) + + _.filter(D2DX_INTERVALS, function(intv) { + return D2DX(intv[0] + (intv[1] - intv[0]) / 2) > 0; + }) + + _.filter(D2DX_INTERVALS, function(intv) { + return D2DX(intv[0] + (intv[1] - intv[0]) / 2) < 0; + }) + + + _.reduce( + sortNumbers(findRootsNumerically(DDX, XRANGE).concat(findRootsNumerically(D2DX, XRANGE))), + function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, + [XRANGE] + ) + + _.filter(COMBINED_INTERVALS, function(intv) { + return PREDICATE(intv[0] + (intv[1] - intv[0]) / 2); + }) + + + _.sortBy(SOLUTION_INTERVALS, function(intv) { + return intv[0] - intv[1]; + })[0] + +
+ +
+
+ Move the blue window to select part of the function. +
+
+ graph.slidingWindow.getX() +
+
+ var correct = _.reduce(_.range(guess, guess + 1, 0.02), function(correct, x) { + return correct && PREDICATE(x); + }, true); + if (!graph.moved && !correct) { + return "" + } + return correct; +
+
+ graph.slidingWindow.moveTo(guess, 0); +
+
+ +

+

+ +
+
+ initAutoscaledGraph([XRANGE, YRANGE]); + addMouseLayer(); + plot(FNX, XRANGE, { + stroke: BLUE, + strokeWidth: 3 + }); + graph.moved = false; + // start the selection at the first zero of f'(x) which is + // guranteed to be wrong but not give info about the right answer + var startX = DDX_INTERVALS[0][1] - 0.5 + graph.slidingWindow = KhanUtil.addRectGraph({ + x: startX, + y: YRANGE[0], + width: 1, + height: YRANGE[1] - YRANGE[0], + normalStyle: { + area: { "fill-opacity": 0.2 }, + edges: { "stroke-width": 0 } + }, + hoverStyle: { + area: { "fill-opacity": 0.3 } + }, + fixed: { + points: [true, true, true, true], + edges: [true, true, true, true] + }, + constraints: { + constrainX: false, + constrainY: true, + xmin: XRANGE[0], + xmax: XRANGE[1] + }, + onMove: function() { + graph.moved = true; + } + }); +
+

+ f(x) = POLYNOMIAL.text() +

+
+ +
+
+
+ function(x) { return DDX(x) > 0 && D2DX(x) > 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f^\prime(x) > 0 and + f^{\prime\prime}(x) > 0. +

+
+

+ The first derivative, f^\prime(x), is greater + than 0 wherever the function is increasing. +

+
+

+ The plural("interval", DDX_INTERVALS_POS.length) + where f(x) is increasing + plural("is", DDX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }); + }); +
+
+

+ The second derivative, f^{\prime\prime}(x), is greater + than 0 wherever the function is concave up. +

+
+

+ The plural("interval", D2DX_INTERVALS_POS.length) + where f(x) is concave up + plural("is", D2DX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(D2DX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return DDX(x) > 0 && D2DX(x) < 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f^\prime(x) > 0 and + f^{\prime\prime}(x) < 0. +

+
+

+ The first derivative, f^\prime(x), is greater + than 0 wherever the function is increasing. +

+
+

+ The plural("interval", DDX_INTERVALS_POS.length) + where f(x) is increasing + plural("is", DDX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }); + }); +
+
+

+ The second derivative, f^{\prime\prime}(x), is less + than 0 wherever the function is concave down. +

+
+

+ The plural("interval", D2DX_INTERVALS_NEG.length) + where f(x) is concave down + plural("is", D2DX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(D2DX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return DDX(x) < 0 && D2DX(x) > 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f^\prime(x) < 0 and + f^{\prime\prime}(x) > 0. +

+
+

+ The first derivative, f^\prime(x), is less + than 0 wherever the function is decreasing. +

+
+

+ The plural("interval", DDX_INTERVALS_NEG.length) + where f(x) is decreasing + plural("is", DDX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }); + }); +
+
+

+ The second derivative, f^{\prime\prime}(x), is greater + than 0 wherever the function is concave up. +

+
+

+ The plural("interval", D2DX_INTERVALS_POS.length) + where f(x) is concave up + plural("is", D2DX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(D2DX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return DDX(x) < 0 && D2DX(x) < 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f^\prime(x) < 0 and + f^{\prime\prime}(x) < 0. +

+
+

+ The first derivative, f^\prime(x), is less + than 0 wherever the function is decreasing. +

+
+

+ The plural("interval", DDX_INTERVALS_NEG.length) + where f(x) is decreasing + plural("is", DDX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }); + }); +
+
+

+ The second derivative, f^{\prime\prime}(x), is less + than 0 wherever the function is concave down. +

+
+

+ The plural("interval", D2DX_INTERVALS_NEG.length) + where f(x) is concave down + plural("is", D2DX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(D2DX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+ +
+ +
538 exercises/recognizing_slope.html
 @@ -0,0 +1,538 @@ + + + + + Recognizing slope + + + + +
+
+ + randFromArray([ + [[ 1, 0, -16, 0, 49], [-5, 5], [-100, 100]], + [[-1, 0, 16, 0, -49], [-5, 5], [-250, 100]], + [[ 1, 3, -14, -35, 21], [-5, 5], [-100, 200]], + [[-1, -3, 14, 35, 0], [-5, 5], [-200, 100]], + [[ 1, 4, -1, -4], [-5, 5], [ -40, 120]], + [[ -1, -4, 1, 4], [-5, 5], [-150, 40]], + [[ 1, 0, -16, 0], [-5, 5], [ -50, 50]], + [[ -1, 0, 16, 0], [-5, 5], [ -70, 60]], + [[ 1, 0, -22, 27], [-5, 5], [ -30, 70]], + [[ -1, 0, 22, -27], [-5, 5], [ -70, 30]], + [[ 1, 1, -13, -14], [-5, 5], [ -40, 40]], + [[ -1, -1, 13, 14], [-5, 5], [ -40, 40]], + [[ 1, 0, -12], [-5, 5], [ -20, 20]], + [[ -1, 0, 12], [-5, 5], [ -20, 20]], + [[ 1, -1, -6], [-5, 5], [ -20, 20]], + [[ -1, 1, 6], [-5, 5], [ -30, 20]], + [[ 1, 0, -3], [-5, 5], [ -20, 30]], + [[ -1, 0, 3], [-5, 5], [ -30, 20]], + [[ 1, 2, 0], [-5, 5], [ -10, 35]], + [[ -1, -2, 0], [-5, 5], [ -40, 20]] + ]) + new Polynomial(0, COEF.length - 1, COEF.reverse()) + + function(x) {return POLYNOMIAL.evalOf(x);} + function(x) {return POLYNOMIAL.derivative().evalOf(x);} + + + _.reduce(findRootsNumerically(FNX, XRANGE), function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, [XRANGE]) + + _.reduce(findRootsNumerically(DDX, XRANGE), function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, [XRANGE]) + + _.filter(FNX_INTERVALS, function(intv) { + return FNX(intv[0] + (intv[1] - intv[0]) / 2) > 0; + }) + + _.filter(FNX_INTERVALS, function(intv) { + return FNX(intv[0] + (intv[1] - intv[0]) / 2) < 0; + }) + + _.filter(DDX_INTERVALS, function(intv) { + return DDX(intv[0] + (intv[1] - intv[0]) / 2) > 0; + }) + + _.filter(DDX_INTERVALS, function(intv) { + return DDX(intv[0] + (intv[1] - intv[0]) / 2) < 0; + }) + + + + _.reduce( + sortNumbers(findRootsNumerically(FNX, XRANGE).concat(findRootsNumerically(DDX, XRANGE))), + function(intervals, root) { + var last = _.last(intervals) + return _.initial(intervals).concat([[last[0], root], [root, last[1]]]); + }, + [XRANGE] + ) + + _.filter(COMBINED_INTERVALS, function(intv) { + return PREDICATE(intv[0] + (intv[1] - intv[0]) / 2); + }) + + + _.sortBy(SOLUTION_INTERVALS, function(intv) { + return intv[0] - intv[1]; + })[0] + +
+ +
+
+ Move the blue window to select part of the function. +
+
+ graph.slidingWindow.getX() +
+
+ var correct = _.reduce(_.range(guess, guess + 1, 0.02), function(correct, x) { + return correct && PREDICATE(x); + }, true); + if (!graph.moved && !correct) { + return "" + } + return correct; +
+
+ graph.slidingWindow.moveTo(guess, 0); +
+
+ +

+

+ +
+
+ initAutoscaledGraph([XRANGE, YRANGE]); + addMouseLayer(); + plot(FNX, XRANGE, { + stroke: BLUE, + strokeWidth: 3 + }); + graph.moved = false; + // start the selection at the first zero of f'(x) which is + // guaranteed to be wrong but not give info about the right answer + var startX = DDX_INTERVALS[0][1] - 0.5; + graph.slidingWindow = KhanUtil.addRectGraph({ + x: startX, + y: YRANGE[0], + width: 1, + height: YRANGE[1] - YRANGE[0], + normalStyle: { + area: { "fill-opacity": 0.2 }, + edges: { "stroke-width": 0 } + }, + hoverStyle: { + area: { "fill-opacity": 0.3 } + }, + fixed: { + points: [true, true, true, true], + edges: [true, true, true, true] + }, + constraints: { + constrainX: false, + constrainY: true, + xmin: XRANGE[0], + xmax: XRANGE[1] + }, + onMove: function() { + graph.moved = true; + } + }); +
+

+ f(x) = POLYNOMIAL.text() +

+
+ +
+
+
+ function(x) { return DDX(x) > 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f^\prime(x) > 0. +

+
+

+ The first derivative, f^\prime(x), is greater + than 0 wherever the function is increasing. +

+
+

+ The plural("interval", DDX_INTERVALS_POS.length) + where f(x) is increasing + plural("is", DDX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return DDX(x) < 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f^\prime(x) < 0. +

+
+

+ The first derivative, f^\prime(x), is less + than 0 wherever the function is decreasing. +

+
+

+ The plural("interval", DDX_INTERVALS_NEG.length) + where f(x) is decreasing + plural("is", DDX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return FNX(x) > 0 && DDX(x) > 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f(x) > 0 and + f^\prime(x) > 0. +

+
+

+ The function f(x) is greater than 0 + wherever it's positive. +

+
+

+ The plural("interval", FNX_INTERVALS_POS.length) + where f(x) is positive + plural("is", FNX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(FNX_INTERVALS_POS, function(interval) { + plot(FNX, [XRANGE[0] - 1, XRANGE[1] + 1], { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }).attr("clip-rect", + scalePoint([range[0][0], range[1][1]])[0] + "," + + scalePoint([range[0][0], range[1][1]])[1] + "," + + scaleVector([range[0][1] - range[0][0], range[1][1]])[0] + "," + + scaleVector([range[0][1] - range[0][0], range[1][1]])[1] + ); + }); +
+
+

+ The first derivative, f^\prime(x), is greater + than 0 wherever the function is increasing. +

+
+

+ The plural("interval", DDX_INTERVALS_POS.length) + where f(x) is increasing + plural("is", DDX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return FNX(x) > 0 && DDX(x) < 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f(x) > 0 and + f^\prime(x) < 0. +

+
+

+ The function f(x) is greater than 0 + wherever it's positive. +

+
+

+ The plural("interval", FNX_INTERVALS_POS.length) + where f(x) is positive + plural("is", FNX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(FNX_INTERVALS_POS, function(interval) { + plot(FNX, [XRANGE[0] - 1, XRANGE[1] + 1], { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }).attr("clip-rect", + scalePoint([range[0][0], range[1][1]])[0] + "," + + scalePoint([range[0][0], range[1][1]])[1] + "," + + scaleVector([range[0][1] - range[0][0], range[1][1]])[0] + "," + + scaleVector([range[0][1] - range[0][0], range[1][1]])[1] + ); + }); +
+
+

+ The first derivative, f^\prime(x), is less + than 0 wherever the function is decreasing. +

+
+

+ The plural("interval", DDX_INTERVALS_NEG.length) + where f(x) is decreasing + plural("is", DDX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return FNX(x) < 0 && DDX(x) > 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f(x) < 0 and + f^\prime(x) > 0. +

+
+

+ The function f(x) is less than 0 + wherever it's negative. +

+
+

+ The plural("interval", FNX_INTERVALS_NEG.length) + where f(x) is negative + plural("is", FNX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(FNX_INTERVALS_NEG, function(interval) { + plot(FNX, [XRANGE[0] - 1, XRANGE[1] + 1], { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }).attr("clip-rect", + scalePoint([range[0][0], 0])[0] + "," + + scalePoint([range[0][0], 0])[1] + "," + + scaleVector([range[0][1] - range[0][0], -range[1][0]])[0] + "," + + scaleVector([range[0][1] - range[0][0], -range[1][0]])[1] + ); + }); +
+
+

+ The first derivative, f^\prime(x), is greater + than 0 wherever the function is increasing. +

+
+

+ The plural("interval", DDX_INTERVALS_POS.length) + where f(x) is increasing + plural("is", DDX_INTERVALS_POS.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_POS, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+
+ function(x) { return FNX(x) < 0 && DDX(x) < 0; } +
+

+ A function f(x) is plotted below. + Highlight an interval where f(x) < 0 and + f^\prime(x) < 0. +

+
+

+ The function f(x) is less than 0 + wherever it's negative. +

+
+

+ The plural("interval", FNX_INTERVALS_NEG.length) + where f(x) is negative + plural("is", FNX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(FNX_INTERVALS_NEG, function(interval) { + plot(FNX, [XRANGE[0] - 1, XRANGE[1] + 1], { + stroke: ORANGE, + strokeWidth: 16, + opacity: 0.7 + }).attr("clip-rect", + scalePoint([range[0][0], 0])[0] + "," + + scalePoint([range[0][0], 0])[1] + "," + + scaleVector([range[0][1] - range[0][0], -range[1][0]])[0] + "," + + scaleVector([range[0][1] - range[0][0], -range[1][0]])[1] + ); + }); +
+
+

+ The first derivative, f^\prime(x), is less + than 0 wherever the function is decreasing. +

+
+

+ The plural("interval", DDX_INTERVALS_NEG.length) + where f(x) is decreasing + plural("is", DDX_INTERVALS_NEG.length) + highlighted above. +

+
+ _.each(DDX_INTERVALS_NEG, function(interval) { + plot(FNX, interval, { + stroke: RED, + strokeWidth: 6, + opacity: 0.8 + }); + }); +
+
+
+

+ Select any part of the function that is highlighted for + both conditions. +

+
+ graph.slidingWindow.moveTo( + (SOLUTION_INTERVAL[1] - SOLUTION_INTERVAL[0]) / 2 + + SOLUTION_INTERVAL[0] - 0.5, 0); +
+
+
+
+ +
+ +
+ +
61 utils/interactive.js
 @@ -76,11 +76,6 @@ $.extend(KhanUtil, { var mouseY = event.pageY -$(graphie.raphael. canvas.parentNode).offset().top; - // can't go beyond 10 pixels from the edge - mouseX = Math.max(10, Math.min(graphie.xpixels - 10, - mouseX)); - mouseY = Math.max(10, Math.min(graphie.ypixels - 10, - mouseY)); return [mouseX, mouseY]; }, @@ -521,8 +516,10 @@ $.extend(KhanUtil, { var scaledPoint = graph.scalePoint(coord); this.visibleShape.attr({ cx: scaledPoint[0] }); this.visibleShape.attr({ cy: scaledPoint[1] }); - this.mouseTarget.attr({ cx: scaledPoint[0] }); - this.mouseTarget.attr({ cy: scaledPoint[1] }); + if (this.mouseTarget != null) { + this.mouseTarget.attr({ cx: scaledPoint[0] }); + this.mouseTarget.attr({ cy: scaledPoint[1] }); + } } this.coord = coord.slice(); }; @@ -530,7 +527,9 @@$.extend(KhanUtil, { // Change z-order to back movablePoint.toBack = function() { if (this.visible) { - this.mouseTarget.toBack(); + if (this.mouseTarget != null) { + this.mouseTarget.toBack(); + } this.visibleShape.toBack(); } }; @@ -538,19 +537,13 @@ $.extend(KhanUtil, { // Change z-order to front movablePoint.toFront = function() { if (this.visible) { - this.mouseTarget.toFront(); + if (this.mouseTarget != null) { + this.mouseTarget.toFront(); + } this.visibleShape.toFront(); } }; - movablePoint.disableDragging = function() { -$(this.mouseTarget[0]).css("display", "none"); - }; - - movablePoint.enableDragging = function() { - $(this.mouseTarget[0]).css("display", "block"); - }; - return movablePoint; }, @@ -1218,8 +1211,8 @@$.extend(KhanUtil, { ymin: null, ymax: null }, - snapX: 1, - snapY: 1, + snapX: 0, + snapY: 0, // this function will be called whenever .translate(), .snap(), or // .moveTo() are called @@ -1370,6 +1363,10 @@ $.extend(KhanUtil, { hoverStyle: rect.hoverStyle.points, snapX: rect.snapX, snapY: rect.snapY, + visible: !rect.fixed.points[i], + constraints: { + fixed: rect.fixed.points[i] + }, onMove: function(x, y) { if (!moveIsInBounds(i, x, y)) { return false; @@ -1379,10 +1376,6 @@$.extend(KhanUtil, { } }); - if (rect.fixed.points[i]) { - point.disableDragging(); - } - rect.points.push(point); }); @@ -1489,9 +1482,15 @@ $.extend(KhanUtil, { _.each(rect.points, function(point, i) { var x0 = point.coord[0]; var y0 = point.coord[1]; + var x1 = x0; + var y1 = y0; - var x1 = KhanUtil.roundToNearest(rect.snapX, x0); - var y1 = KhanUtil.roundToNearest(rect.snapY, y0); + if (rect.snapX) { + x1 = KhanUtil.roundToNearest(rect.snapX, x0); + } + if (rect.snapY) { + y1 = KhanUtil.roundToNearest(rect.snapY, y0); + } if (!dx || !dy) { dx = x1 - x0; @@ -1575,7 +1574,7 @@$.extend(KhanUtil, { (event.which === 1 || event.which === 0)) { event.preventDefault(); rect.toFront(); - rect.prevCoord = KhanUtil.getMouseCoord(event); + rect.prevCoord = KhanUtil.getMouseCoord(event); rect.enableHoverStyle(); @@ -1585,7 +1584,7 @@ $.extend(KhanUtil, { KhanUtil.dragging = true; if (event.type === "vmousemove") { - var currCoord = KhanUtil.getMouseCoord(event); + var currCoord = KhanUtil.getMouseCoord(event); if (rect.prevCoord && rect.prevCoord.length === 2) { var diff = KhanUtil.coordDiff(rect.prevCoord, currCoord); @@ -1599,7 +1598,13 @@$.extend(KhanUtil, { rect.dragging = false; KhanUtil.dragging = false; - rect.enableNormalStyle(); + var currCoord = KhanUtil.getMouseCoord(event); + if (currCoord[0] < rect.getX() || + currCoord[0] > rect.getX2() || + currCoord[1] < rect.getY() || + currCoord[1] > rect.getY2()) { + rect.enableNormalStyle(); + } // snap to grid rect.snap();
13 utils/math.js
 @@ -504,6 +504,19 @@ $.extend(KhanUtil, { }); }, + tagMarkup: function(val, tag, attr) { + attr = attr || ""; + return "<" + tag + " " + attr + ">" + val + ""; + }, + + /** + * Add hint color markup to a given value + */ + hintColorMarkup: function(val, colorName) { + var hintCSS = "class='hint_" + colorName + "'"; + return KhanUtil.tagMarkup(val, "span", hintCSS); + }, + BLUE: "#6495ED", ORANGE: "#FFA500", PINK: "#FF00AF", 31 utils/polynomials.js  @@ -149,18 +149,18 @@$.extend(KhanUtil, { }; this.derivative = function() { + var self = this; var ddxCoefs = []; - - for (var i = this.maxDegree; i >= this.minDegree; i--) { - ddxCoefs[i - 1] = i * this.coefs[i]; - } + _.each(_.range(self.maxDegree - self.minDegree + 1), function(i) { + ddxCoefs[i - 1] = i * self.coefs[i]; + }); // if the term's degree is zero, the derivative degree is not // decremented - var ddxMinDegree = this.minDegree ? this.minDegree - 1 : 0; - var ddxMaxDegree = this.maxDegree ? this.maxDegree - 1 : 0; + var ddxMinDegree = self.minDegree ? self.minDegree - 1 : 0; + var ddxMaxDegree = self.maxDegree ? self.maxDegree - 1 : 0; - return new KhanUtil.Polynomial(ddxMinDegree, ddxMaxDegree, ddxCoefs, this.variable); + return new KhanUtil.Polynomial(ddxMinDegree, ddxMaxDegree, ddxCoefs, self.variable); }, /** @@ -390,5 +390,20 @@ \$.extend(KhanUtil, { } return allZero ? randCoefs(minDegree, maxDegree) : coefs; - } + }, + + findRootsNumerically: function(fn, range, step) { + step = step || 0.05; + var x = range[0] + var positive = fn(x) > 0; + var roots = []; + while (x < range[1]) { + x += step; + if ((fn(x) > 0) !== positive) { + roots.push(KhanUtil.roundToNearest(step, x - step)); + positive = !positive; + } + } + return roots; + }, });