# Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

# Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
• 13 commits
• 6 files changed
• 5 contributors
Commits on Aug 06, 2012
 xymostech Remove report logging b895cd9 xymostech Merge pull request #27482 from xymostech/remove-logs Remove report logging 4079c63
Commits on Aug 07, 2012
 xymostech Add exercise "Views of a function" Summary: Add three problem types of converting functions between differnt forms: graph to table table to graph equation to table Test Plan: I tested in Chrome dev, but nothing fancy, so it should work Reviewers: eater, mark, omar Reviewed By: mark Differential Revision: http://phabricator.khanacademy.org/D477 b7691c4 beneater Use "neither" instead of "none" when referring to 2 people Reviewers: mark Reviewed By: mark Differential Revision: http://phabricator.khanacademy.org/D532 33c1c96 spicyj Fix views_of_a_function compilation 2687eeb xymostech Stop all the dumb garbage collection I don't see any weird side effects of this, and it returns 0 like normal as well. I think it should be safe, but someone might want to do some additional checking. c5dc718 xymostech Merge pull request #27555 from xymostech/fix-pack Stop all the dumb garbage collection in build/pack.rb f13e3d9 xymostech Make build/pack.rb return 0 on success 9e4a4b9
Commits on Aug 08, 2012
 Sohl-Dickstein Modified the array of possible jump lengths for moving through questi… …ons so that all of them are coprime with the number of question bins. This guarantees that users will not repeat a question until they have seen 'bins' questions. Reference Ben Alpert Reviewers: alpert CC: eater, jace Differential Revision: http://phabricator.khanacademy.org/D548 1293c32 Sohl-Dickstein Modified the array of possible jump lengths for moving through questi… …ons so that all of them are coprime with the number of question bins. This guarantees that users will not repeat a question until they have seen 'bins' questions. Reference Ben Alpert Reviewers: alpert Reviewed By: alpert CC: eater, jace Differential Revision: http://phabricator.khanacademy.org/D548 eabb716 beneater Add khanscript! Summary: You can now create
Commits on Aug 09, 2012
 mwittels add expected value exercise Reviewers: eater Reviewed By: eater CC: emily Differential Revision: http://phabricator.khanacademy.org/D531 260074b`
2 build/pack.rb
 @@ -156,3 +156,5 @@ def uglifier_insane f.write doc.to_html end end + +exit! 0
5 exercises/dependent_probability.html
 @@ -86,8 +86,9 @@

If the teacher chooses CHOSEN students, what is the probability that - ALL ? ((CHOSEN === 2) ? "both" : "all") : "none" - of them EVENT_PY? + ALL ? ((CHOSEN === 2) ? "both" : "all") : + ((CHOSEN === 2) ? "neither" : "none") + of them EVENT_PY?

294 exercises/expected_value.html
 @@ -0,0 +1,294 @@ + + + + + Expected Value + + + +
+ +
+
+
+ randFromArray([ + ["a 1", 1], + ["a 2", 1], + ["a 3", 1], + ["a 4", 1], + ["a 5", 1], + ["a 6", 1], + ["a 7", 1], + ["an 8", 1], + ["a 9", 1], + ["a 10", 1], + ["at least a 2", 9], + ["at least a 5", 6], + ["at least a 7", 4], + ["more than a 2", 8], + ["more than a 6", 4], + ["more than an 8", 2], + ["less than a 4", 3], + ["less than a 7", 6], + ["less than an 8", 7], + ["an even number", 5], + ["an even number", 5], + ["an odd number", 5], + ["an odd number", 5] + ]) + 10 - MAKE_COUNT + fraction(MAKE_COUNT,10,true,false) + fraction(LOSE_COUNT,10,true,false) + randRange(5,10) + randRange(5,10) + MAKE_COUNT*MAKE - LOSE_COUNT*LOSE + + [fraction(PROFIT,10,true,false), + (PROFIT/10).toFixed(2)] + +
+ +

+ A game at the carnival offers these odds: you get to roll a + ten-sided die, and if you roll RESULT_DESC, + you make MAKE dollars. Unfortunately, + if you roll anything else, you lose + LOSE dollars. +

+ +

+ How much money do you expect to make (or lose) + playing this game? +

+ +
+ $+ ANS + + + + + The expected value of an event (like playing this game) + is average of the values of each outcome. Since some + outcomes are more likely than others (sometimes), we + weight the value of each outcome according to its + probability to get an accurate idea of what value + to expect. + + + There are two events that can happen in this game: either + you roll RESULT_DESC, or you don't. So, the + expected value will look like this: + + E = + (money gained when you roll RESULT_DESC) + \cdot + (probability of rolling RESULT_DESC) + + + (money gained when you don't roll RESULT_DESC) + \cdot + (probability of not rolling RESULT_DESC). + + + The money you gain when you win + is$MAKE. + The probability of winning is the probability + that you roll RESULT_DESC. +

+

+ This probability is the number of winning outcomes + divided by the total number of + outcomes, MAKE_FR. +

+

+ The money you gain when you lose is + $-LOSE + (since you actually lose money). The probability that + you lose is the probability that you don't roll + RESULT_DESC. + + + This probability must be + 1 - MAKE_FR = LOSE_FR. + + + So, if we take the average of the amount of money you make + on each outcome, weighted by how probable each outcome is, + we get the expected amount of money you will make: + (MAKE\cdotMAKE_FR) + + (-LOSE\cdotLOSE_FR) = +$ANS_F = $ANS. + + + + + + + randFromArray([4,6,10,12]) + + (function(){ + if(SIDES < 7) { + return _.map(_.range(SIDES), function(i){ + return "\\dfrac{"+(i+1)+"}{"+SIDES+"}"; }) + .join("+"); + } + + first = _.map(_.range(3), function(i){ + return "\\dfrac{"+(i+1)+"}{"+SIDES+"}"; }) + .join("+"); + last = _.map(_.range(3), function(i){ + return "\\dfrac{"+(SIDES-2+i)+"}{"+SIDES+"}"; }).join("+"); + return [first,"\\cdots",last].join("+"); + })() + + + _.reduce(_.range(SIDES), function(n,i){ return n+i+1; }, 0) + + + + If you roll a SIDES-sided die, what is the expected + value you will roll? + + + + ANS_N/SIDES + + + + + The expected value of an event (like rolling a die) + is average of the values of each outcome. To get an + accurate idea of what value of expect, we + weight the value of each outcome according to its + probability. + + + In this case, there are SIDES outcomes: + the first outcome is rolling a 1, the second outcome is + rolling a 2, and so on. The value of each of these outcomes + is just the number you roll. + + + So, the value of the first outcome is 1, and its + probability is \dfrac{1}{SIDES}. + + + The value of the second outcome is 2, the value of + the third outcome is 3, and so on. There are + SIDES outcomes altogether, and each of them + occurs with probability + \dfrac{1}{SIDES}. + + + So, if we average the values of each of these outcomes, + we get the expected value we will roll, which is + SUM = + mixedFractionFromImproper(ANS_N,SIDES,true,true). + + + + + + random() < 0.4 + randRange(2,4) + randRange(1,5)*100 + BUY ? + COST*ODDS + randRange(1,3)*100 : + COST*ODDS - randRange(1,3)*100 + + fraction(1,ODDS,true,true) + BUY ? + "Yes, the expected value is positive." : + "No, the expected value is negative." + + + + + You decide you're only going to buy a lottery ticket if the + expected amount of money you will get is positive. Tickets + cost$COST, and you get + $PRIZE if you win. The odds of + winning are 1 in ODDS, + meaning that you will win with probability + ODD_F. + + + + Should you buy a ticket for this lottery? + + + + ANS + + + + • Yes, the expected value is positive. • + • No, the expected value is negative. • + + + + + The expected value of an event (like buying a lottery + ticket) is the average of the values of each outcome. + In this case, the outcome where you win is much less likely + than the outcome that you lose. So, to get an accurate idea + of how much money you expect to win or lose, we have to + take an average weighted by the probability of each outcome. + + + As an equation, this means the expected amount of money + you will win is + E = (money gained when you win) + \cdot (probability of winning) + + (money gained when you lose) + \cdot (probability of losing) + . + + + Let's figure out each of these terms one at a time. The + money you gain when you win is your winnings minus the + cost of the ticket,$PRIZE - + $COST (you may find the math easier + if you don't simplify this). + + + From the question, we know the probability of winning is + ODD_F. + + + The money you gain when you lose is actually negative, + and is just the cost of the ticket, + -$COST. +

+

+ Finally, the probability of losing is (1 - + ODD_F) (you may find the math + easier if you don't simplify this). +

+

+ Putting it all together, the expected value is + E = ($PRIZE -$COST) + (ODD_F) + (-$COST) + (1 - ODD_F) = +$ \dfrac{PRIZE} + {ODDS} - $\cancel{\dfrac{COST} + {ODDS}} -$COST + + $\cancel{\dfrac{COST}{ODDS}} = +$fraction(PRIZE,ODDS,true,true) - + $COST. + + +$fraction(PRIZE,ODDS,true,true) - + $COST is + PRIZE/ODDS - COST > 0 ? "positive" : "negative". + + So, we expect to PRIZE/ODDS - COST > 0 ? "make" : "lose" money by buying a lottery ticket, because + the expected value is PRIZE/ODDS - COST > 0 ? + "positive" : "negative". + + + + + + + 515 exercises/views_of_a_function.html  @@ -0,0 +1,515 @@ + + + + + Views of a function + + + + + + + + randRangeNonZero(-3, 3) + randRangeNonZero(-3, 3) + randRangeNonZero(-3, 3) + function(a) { + return (a === 1) ? "" : (a === -1) ? "-" : a; + } + [SIGNIFY(A), SIGNIFY(B), SIGNIFY(C)] + randFromArray([ + [function(x) { + return B * x + C; + }, BSHOW + " x + " + C], + [function(x) { + return B / 2 * x * x + A * x + C; + }, ((B === 2) ? "" : (B === -2) ? "-" : (B / 2)) + + " x^2 + " + ASHOW + " x + " + C], + [function(x) { + return B * sin(C * x / Math.PI) + A; + }, BSHOW + " \\sin\\left(" + CSHOW + " x / \\pi\\right) + " + A], + [function(x) { + return B * pow(Math.E, C * x / 3) + A; + }, BSHOW + "e^{" + + ((abs(C) === 3) ? SIGNIFY(C/3) + "x" : CSHOW + " x / 3") + + "} + " + A] + ]) + (function() { + var xs = chooseXValues(FUNC, 1); + if (xs.length >= 5) { + return sortNumbers(shuffle(xs, 5)); + } else { + xs = chooseXValues(FUNC, 2); + return sortNumbers(shuffle(xs, 5)); + } + })() + + + + + 0.5 + + + Create a table of values for the function in the graph below. + Use at least 5 different points. Enter the values in the table + as decimals. + + + + graphInit({ + range: 10, + scale: 20, + tickStep: 1, + labelStep: 1, + unityLabels: false, + labelFormat: function(s) { + return "\\small{" + s + "}"; + }, + axisArrows: "<->" + }); + + plot(FUNC, [-10, 10], { stroke: BLUE }); + + + + + Enter your data in the table below. + + xy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (function(){ + var guess = []; +$(".ttable tr").each(function() { + var input = []; + $(this).children().each(function() { + input.push($(this).children().val()); + }); + guess.push(input); + }); + return guess; + })() +
+
+ var attempted = 0; + var correct = 0; + var xs = []; + + for (var i = 0; i < 8; ++i) { + if ($.trim(guess[i][0]) !== "" && +$.trim(guess[i][1]) !== "") { + attempted += 1; + + var x = parseFloat(guess[i][0]), + y = parseFloat(guess[i][1]); + + if (abs(FUNC(x) - y) < CORRECTOFFSET) { + correct += 1; + xs.push(x); + } + } + } + + if (attempted < 5) { + return "You must enter 5 or more points"; + } + + xs = KhanUtil.sortNumbers(xs); + var different = 1; + + for (var i = 0; i < correct - 1; ++i) { + if (xs[i + 1] - xs[i] >= 0.5) { + different += 1; + } + } + + return different === attempted; +
+ + +
+

You can look at function in many different ways, including a + graph and a table. Here, we have a function modeled in a + graph, and we want to store some information about it at a + couple points by modeling it as a table.

+

To represent it as a table, take any five points on the + graph, and list them in the table.

+

For example, we can look at the point with an + x-value of + EXAMPLES[0].

+
+

The y-value at this point is + round(2 * FUNC(EXAMPLES[0])) / 2, + which we find from the graph.

+
+ line([EXAMPLES[0], -11], [EXAMPLES[0], 11], + { strokeWidth: 1, stroke: ORANGE }); + circle([EXAMPLES[0], FUNC(EXAMPLES[0])], 0.2, + { stroke: ORANGE, fill: ORANGE }); +
+
+

+ To record this in our table, put + EXAMPLES[0] in the x + column, and + round(2 * FUNC(EXAMPLES[0])) / 2 + in the y column. +

+

+ We can do this with 4 other x-values, such as + EXAMPLES[1], + EXAMPLES[2], + EXAMPLES[3], + and EXAMPLES[4]. +

+
+

We can find the y-values at these points + by finding them on the graph as well.

+
+ for (var i = 1; i < 5; ++i) { + line([EXAMPLES[i], -11], [EXAMPLES[i], 11], + { strokeWidth: 1, stroke: ORANGE }); + circle([EXAMPLES[i], FUNC(EXAMPLES[i])], 0.2, + { stroke: ORANGE, fill: ORANGE }); + } +
+
+
+

From this, five points on the graph are:

+
+

+ (x, round(FUNC(x) * 2) / 2) +

+
+
+
+ + +
+

Create a graph for the function that is modeled + below by plotting the points on the graph.

+ +
+ +
+ x + + y +
+ x+"\\hphantom{.0}" + + + roundToNearest(0.5, FUNC(x)).toFixed(1) + .replace(/\.0$/, "\\hphantom{.0}") + + + + + + + + + + + + graphInit({ + range: 10, + scale: 20, + tickStep: 1, + labelStep: 1, + unityLabels: false, + labelFormat: function(s) { + return "\\small{" + s + "}"; + }, + axisArrows: "<->" + }); + + addMouseLayer(); + + graph.points = []; + + var drawn = false; + + graph.graphFunc = function() { + if (!drawn) { + drawn = true; + var func = plot(FUNC, [-10, 10], + { stroke: ORANGE, opacity: 0.0 }); + func.animate({ opacity: 1.0 }, 800); + } + + _.invoke(graph.points, "toFront"); + }; + + graph.checkAnswer = function() { + var used = [false, false, false, false, false]; + + _.each(EXAMPLES, function(x) { + var y = roundToNearest(0.5, FUNC(x)); + var done = false; + _.each(graph.points, function(pt, i) { + if (!done) { + var coord = pt.coord; + if (coord[0] === x && + coord[1] === y) { + used[i] = true; + done = true; + } + } + }); + }); + + return _.all(used, _.identity); + }; + + graph.moved = false; + + graph.checkPoints = function() { + if (graph.checkAnswer()) { + graph.graphFunc(); + } + + graph.moved = true; + + return true; + }; + + for (var i = 0; i < 5; ++i) { + graph.points.push(addMovablePoint({ + coord: [2 * i - 4, 0], + snapX: 0.5, + snapY: 0.5, + onMoveEnd: graph.checkPoints + })); + } + + + + + + Plot the points given in the table on the graph, + then check your answer. + + + [ + graph.moved, + graph.checkAnswer(), + _.pluck(graph.points, "coord") + ] + + + console.log(guess); + if (!guess[0]) { + return ""; + } else { + return guess[1]; + } + + + _.each(graph.points, function(pt, i) { + pt.setCoord(guess[2][i]); + }); + + + + We can look at a function in many different ways, including + a table and a graph. Here, we have information about a + function at a few points, and we are trying to gain a more + general view of the function by plotting those points in a + graph. + + To represent it as a graph, take all the points listed in + the table, and plot them on the graph. + For example, let's look at the point + + (EXAMPLES[0], + roundToNearest(0.5, FUNC(EXAMPLES[0]))) + . + + + We need to move one of the points to this position to + represent plotting it on the graph. + + var endpt = [EXAMPLES[0], + roundToNearest(0.5, FUNC(EXAMPLES[0]))]; + + line([-4, 0], endpt, { arrows: "->" }); + graph.points[0].moveTo(endpt[0], endpt[1]); + + graph.points[0].toFront(); + + + + Now, plot the remaining four points by placing the + remaining points on the given 'X's. + + for (var i = 1; i < 5; ++i) { + var x = EXAMPLES[i]; + var y = roundToNearest(0.5, FUNC(x)); + + line([x - 0.5, y - 0.5], [x + 0.5, y + 0.5], { + stroke: PINK + }); + line([x + 0.5, y - 0.5], [x - 0.5, y + 0.5], { + stroke: PINK + }); + + _.invoke(graph.points, "toFront"); + } + + + + + + + randFromArray([ + [function(x) { + return B * x + C; + }, BSHOW + " x + " + C], + [function(x) { + return B / 2 * x * x + A * x + C; + }, ((B === 2) ? "" : (B === -2) ? "-" : (B / 2)) + + " x^2 + " + ASHOW + " x + " + C] + ]) + (function() { + var xs = chooseXValues(FUNC, 1); + if (xs.length >= 5) { + return sortNumbers(shuffle(xs, 5)); + } else { + xs = chooseXValues(FUNC, 2); + return sortNumbers(shuffle(xs, 5)); + } + })() + 0.01 + + + Create a table with at least five different points in it + created from the function. Enter the values in the table as + decimals. + + FUNCSHOW + + You can look at a function in many different ways, + including an equation and a table. We have an equation, + and in order to see more clearly how the function acts at + few points, we are going to record information about it in + a table. + To represent it as a table, pick some x values + to plug into the equation, and record that x + and the result of plugging it into the equation + in the table. + For example, try plugging in + EXAMPLES[0] to the equation. + + The result of f(EXAMPLES[0]) is + roundToNearest(0.1, FUNC(EXAMPLES[0])). + Record this in the table by putting + EXAMPLES[0] in the x + column, and + roundToNearest(0.1, FUNC(EXAMPLES[0])) + in the cooresponding y column. + + + Now, choose four more x values to plug into + the equation. Let's try the numbers + EXAMPLES[1], + EXAMPLES[2], + EXAMPLES[3], + and EXAMPLES[4]. + + + By plugging into the equation, we get: + + f(x) = + roundToNearest(0.1, FUNC(x)) + + + + + + + + 13 khan-exercise.js  @@ -75,8 +75,11 @@ var Khan = (function() { }); } - // Prime numbers used for jumping through exercises - var primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + // Numbers which are coprime to the number of bins, used for jumping through + // exercises. To quickly test a number in python use code like: + // import fractions + // fractions.gcd( 197, 200) + var primes = [197, 3, 193, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83], /* @@ -163,7 +166,9 @@ var Khan = (function() { exerciseName = deslugify(exerciseId), // Bin users into a certain number of realms so that - // there is some level of reproducability in their questions + // there is some level of reproducability in their questions. + // If you change this, make sure all entries in the array "primes" + // set above are coprime to the new value. bins = 200, // Number of past problems to consider when avoiding duplicates @@ -2237,7 +2242,7 @@ var Khan = (function() { ("loaded, " + (MathJax.isReady ? "" : "NOT ") + "ready, queue length: " + MathJax.Hub.queue.queue.length)), sessionStorageInfo = (typeof sessionStorage === "undefined" || typeof sessionStorage.getItem === "undefined" ? "sessionStorage NOT enabled" : null), warningInfo =$("#warning-bar-content").text(), - parts = [$("#issue-body").val() || null, pathlink, historyLink, " " + JSON.stringify(guessLog), agent, sessionStorageInfo, mathjaxInfo, warningInfo, debugLogLog.join("\n")], + parts = [$("#issue-body").val() || null, pathlink, historyLink, " " + JSON.stringify(guessLog), agent, sessionStorageInfo, mathjaxInfo, warningInfo], body = $.grep(parts, function(e) { return e != null; }).join("\n\n"); var mathjaxLoadFailures =$.map(MathJax.Ajax.loading, function(info, script) {
9 utils/khanscript.js
 @@ -0,0 +1,9 @@ +(function() { + $.fn.khanscript = function(problem) { + return this.find("script[type='text/khanscript']").each(function() { + var code =$(this).text(); + code = "(function() {" + code + "})()"; + \$.tmpl.getVAR(code); + }).end(); + }; +})();