Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

figure out what to do about errors from rounding midway through #64

Open
evykassirer opened this issue Dec 30, 2016 · 20 comments
Open

figure out what to do about errors from rounding midway through #64

evykassirer opened this issue Dec 30, 2016 · 20 comments

Comments

@evykassirer
Copy link
Contributor

evykassirer commented Dec 30, 2016

Blocked on a new parse tree that Kevin is working on. When we have the new tree, we'll be able to add clearer information about approximate values and won't have to round!


so it's good pedagogically to round partway through, but then we can get the wrong answer in the end!

e.g. this gives us 6.399 when it should actually be 6.4 :(

x - 3.4 = ( x - 2.5)/( 1.3)

steps (approximately, to give an idea of why this happens):

  • x - 3.4 = x/1.3 - 2.5/1.3
  • x - 3.4 = x/1.3 - 1.9231 (maybe we wouldn't divide here, but how would we make that call easily?)
  • ...
  • (1 - 1/1.3) x = 3.4 - 1.9231
  • ...
  • 0.2308x = 1.4769
  • ...
  • x = 6.399

I'm not really sure what the best pedagogical solution is! having really long numbers in the middle wouldn't really be great. What would we want to show the user?

@kevinbarabash
Copy link
Contributor

@evykassirer great project!

In this case you could multiply both sides by 1.3, but that's not a very general solution. You probably want to use a bignum library, there are a couple written in JS. I forgot which one I used, but it stored decimals as fractions which should get around this problem. There's still the question of what to display to students. Maybe you could use ellipsis when presenting decimals that continue, or, even better, a bar over the repeating part. In this case 1.9230769230769 the 230769 repeats.

@evykassirer
Copy link
Contributor Author

thanks Kevin! :)

oo the bar or ellipses sounds like a nice solution.

Although I think the reason we started rounding in the first place was floating point errors - that's what the bignum library is for right?

Storing decimals as fractions miiiight not work for all cases - e.g. square roots giving irrational numbers (but I think right now it keeps it as a square root and doesn't calculate it)

@kevinbarabash
Copy link
Contributor

Although I think the reason we started rounding in the first place was floating point errors - that's what the bignum library is for right?

Right.

right now it keeps it as a square root and doesn't calculate it

Excellent!

@hmaurer
Copy link
Contributor

hmaurer commented Jan 20, 2017

Hello! Throwing some thoughts in: ellipsis are an elegant solution if the goal is to obtain an exact result, but sometimes when doing simple arithmetic we only care about an approximate result. As @evykassirer mentioned in those cases it makes sense to round midway.

Maybe at that point the system could mark all subsequent nodes as "approximate", so that instead of displaying equality signs to the user we may display "≈" signs.

An extra-awesome feature (which would be particularly useful when doing physics-related arithmetic) would be to keep track of the error-margin for each step. Probably outside the scope of this project for now though.

@kevinbarabash
Copy link
Contributor

@hmaurer I agree that sometimes it makes more sense to round and use "≈". It would be nice both approaches were available and configurable.

@kevinbarabash
Copy link
Contributor

@evykassirer would you be interested in a PR for integrating a bignum library? I can make it optional. What would be a good way to specify options?

@evykassirer
Copy link
Contributor Author

Hello! Great discussion 🔢 I like these ideas


re "≈":

Since there's no "=" between steps (for expressions), just a list of steps, I think the way it would work is that we'd label the nodes (like @hmaurer said) as approximate, and the user of mathsteps could then choose to use "≈" in showing the steps to the user. Still not sure what the best way to design that "label" is, so that it's easy to use and understand.

Also, I guess equations would be different because there is an equals sign. So would we want to use as the comparator instead once we know the two sides aren't equal anymore? What if the comparator was originally <? (e.g. 2x/3 < 4 --> 0.666x approx< 4)


re bignum:

@kevinbarabash I think that would be a great idea. Interested in @aelnaiem's thoughts (he was my mentor at Socratic and has worked on this project, so he might want to have input on this).

So just to confirm, it would work like this?

  • if selected as an option (tbd how we'll do this),
  • numbers will no longer be rounded, but will be accurate because of bignum
  • when displayed to students, developers using mathsteps will want to add elipses after a certain precision for these bignums, if they don't want the number to be really long when it's printed (right now, there's no custom printing in mathsteps to asciimath or latex for expressions, just the built in toString and toTex from mathjs, so maybe we'd create printing functions that adds the elipses for them too?)

There aren't really any global options for mathsteps right now, but this would be nice to be one if we don't want to send a parameter through all the function calls (though perhaps it could be argued that this is the better way to do it? feels annoying to me). Are there standards for global options that can be configured in npm modules?

From a quick Google search it seems like one option is creating a file called Options.js and expose a function mathsteps.setOptions() which writes to a file, and then before rounding we could call Options.shouldRound() which would read from the file. Open to more elegant solutions though :)

@kevinbarabash
Copy link
Contributor

@evykassirer math.js has bignum functions built into. I'm going to use those so that we don't introduce another dependency. As for options, I think it's probably useful to have both mathsteps.setOptions and the ability to pass options directly to simplifyExpression and solveEquation.

@evykassirer
Copy link
Contributor Author

Oh perfect, thanks math.js!

Sounds good to me. Ahmed ( my mentor from last term @aelnaiem, who was overseeing general math stuff at Socratic ) was on vacation last week, so we haven't figured out how much say he'll have in decisions around stuff like this - so I'd like to check in with him before we merge, but I'm pretty sure it'll be fine so feel free to start working on it if you like :)

thanks so much 😸

@kevinbarabash
Copy link
Contributor

After doing some digging it turns out math.js' bignum is arbitrary precision math and doesn't use fractions. Thankfully, math.js also as a fraction library. I'm going to give that a try instead.

@kevinbarabash
Copy link
Contributor

Something else to consider, with this particular equation x - 3.4 = ( x - 2.5)/( 1.3), the rounding issue could be avoided by multiplying both sides by 1.3. This is the approach I'd take if I was solving this by hand. @evykassirer was this a pedagogical choice or a limitation of the current algorithm?

@evykassirer
Copy link
Contributor Author

Yes, good point. I'd do the same as you. Definitely a limitation of algorithm.

Pretty much, we implemented equation support pretty naively and simplify both sides completely (the same way we simplify expressions) and then move things around one step at a time. I think the pedagogy for equations has a lot that can be worked on, and will probably complicate the codebase a bit. Will be fun to think about and work on in the near future :) We could maybe open and issue with this example ("improve equation pedagogy" or something) to brainstorm this stuff more

@hmaurer
Copy link
Contributor

hmaurer commented Jan 22, 2017

@evykassirer It could be discussed in #49

@evykassirer
Copy link
Contributor Author

#49 is related, but I see it more as a special case of equation support

I'd still like to have some general discussion where we can think about equation pedagogy and figure out what changes should be made to existing supported equations (like what Kevin was talking about) and new ones we don't support yet (e.g. #49 and #48 )

@hmaurer
Copy link
Contributor

hmaurer commented Jan 22, 2017

@evykassirer ah, yes. A discussion on the pedagogy of solving equations / simplifying will also touch to #45. I'll wait until an issue is created to talk about it, but as a quick question: should we be concerned about handling non-linear (e.g. quadratic) equations?

@evykassirer
Copy link
Contributor Author

@kevinbarabash do you know if this issue is fixable before the new tree? or should we have it blocked on that

@kevinbarabash
Copy link
Contributor

@evykassirer I think this will be easier to tackle afterwards if we want to use fraction.js. If we're okay with marking values as approximate then we could probably add that to the current system without to much effort. It wouldn't be an extra prop we'd have to copy whenever evaluating values. If any operand is marked as an approximate value than the result of the operation involving that operand would also be marked as an approximate value.

@evykassirer
Copy link
Contributor Author

I'll leave this as blocked for now then, and if the tree is taking a while or there's less work to be done elsewhere, I'll open an issue for that solution in the meantime :)

Thanks!

@tkosan
Copy link
Contributor

tkosan commented Jul 8, 2017

This is an alternative way to solve this problem:

          x + -3.4 = (x + -2.5)/1.3                                              the problem
Step  1:  x + -3.4 + -((x + -2.5)/1.3) = (x + -2.5)/1.3 + -((x + -2.5)/1.3)      subtract
Step  2:  x + -3.4 + (2.5 + -x)/1.3 = (x + -2.5)/1.3 + (2.5 + -x)/1.3            -(a-b)/c = (b-a)/c
Step  3:  (1.3*x + -(1.3*3.4) + 2.5 + -x)/1.3 = (x + -2.5)/1.3 + (2.5 + -x)/1.3  common denominator
Step  4:  (1.3*x + -1.92 + -x)/1.3 = (x + -2.5)/1.3 + (2.5 + -x)/1.3             arithmetic
Step  5:  (0.3*x + -1.92)/1.3 = (x + -2.5)/1.3 + (2.5 + -x)/1.3                  collect like terms
Step  6:  (0.3*x + -1.92)/1.3 = (x + -2.5 + 2.5 + -x)/1.3                        a/c + b/c = (a+b)/c
Step  7:  1.3*(0.3*x + -1.92) = 1.3*(x + -2.5 + 2.5 + -x)                        cross multiply
Step  8:  0.39*x + -2.496 = 1.3*(x + -2.5 + 2.5 + -x)                            a(b+c)=ab+ac
Step  9:  0.39*x + -2.496 = 1.3*(x + -2.5 + 2.5 + -x)                            regroup terms
Step 10:  0.39*x + -2.496 = 1.3*(x + 0 + -x)                                     arithmetic
Step 11:  0.39*x + -2.496 = 1.3*(x + -x)                                         x+0 = x
Step 12:  0.39*x + -2.496 = 1.3*0                                                cancel x
Step 13:  0.39*x + -2.496 + 2.496 = 1.3*0 + 2.496                                add 2.496
Step 14:  0.39*x = 1.3*0 + 2.496 + -2.496 + 2.496                                add -2.496+2.496
Step 15:  0.39*x = 1.3*0 + 2.496                                                 cancel 2.496
Step 16:  0.39*x = 2.496                                                         arithmetic
Step 17:  x = 6.4                                                                divide by 0.39

@tkosan
Copy link
Contributor

tkosan commented Jul 8, 2017

This solution performs division in step 2:

          x + -3.4 = (x + -2.5)/1.3                                     the problem
Step  1:  x + -3.4 = x/1.3 + -(2.5/1.3)                                 (a±b)/c = a/c ± b/c
Step  2:  x + -3.4 = x/1.3 + -1.923077                                  arithmetic
Step  3:  x + -3.4 + -(x/1.3) = x/1.3 + -1.923077 + -(x/1.3)            subtract x/1.3
Step  4:  (1.3*x + -(1.3*3.4) + -x)/1.3 = x/1.3 + -1.923077 + -(x/1.3)  common denominator
Step  5:  (1.3*x + -4.42 + -x)/1.3 = x/1.3 + -1.923077 + -(x/1.3)       arithmetic
Step  6:  (0.3*x + -4.42)/1.3 = x/1.3 + -1.923077 + -(x/1.3)            collect like terms
Step  7:  (0.3*x + -4.42)/1.3 = -1.923077                               cancel x/1.3
Step  8:  0.3*x + -4.42 = -2.5                                          multiply by 1.3
Step  9:  0.3*x + -4.42 + 4.42 = -2.5 + 4.42                            add 4.42
Step 10:  0.3*x + 0 = 1.92                                              arithmetic
Step 11:  0.3*x = 1.92                                                  x+0 = x
Step 12:  x = 6.4                                                       divide by 0.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants