mkulesh / microMathematics

microMathematics Plus - Extended visual calculator
GNU General Public License v3.0
561 stars 68 forks source link

Loss of one point from the interval when using some decimal prefixes #100

Closed mmaxs closed 3 years ago

mmaxs commented 3 years ago

Example (look at xcm, xmm, xfm, xam): IMG_20201130_215638

b.interval1.mmt.zip

mkulesh commented 3 years ago

Hi @mmaxs, thank you for the observation. I will try to analyze it asap.

mkulesh commented 3 years ago

Hi @mmaxs, I fixed the issue. Could you please install the latest build https://github.com/mkulesh/microMathematics/raw/autobuild/autobuild/microMathematics-v2.20.2-debug.apk and test how does it work? intervals

mkulesh commented 3 years ago

Hi @mmaxs

I've just tested this and it doesn't settle the issue. Try i1 = [1, 2 .. 4.4], and it will be = [1 2 3 4.4] (missing of 4). I'm looking at the code and I think that you are overcomplicating the estimation of N. I suspect, it should be merely 1 + ceil((max - min) / delta). Doesn't it?

Unfortunately it is not too easy. From any reason I decided to always add the last point to the interval (i.e 4.4 will be always added at the and of the interval). In this case just ceil may have a rounding problem that results in an extra point at the end. This corner case is testes within the automatic test ts_interval.mmt from the app resources (that is only visible in developer mode).

Now i modified the calculation of the points number. It works now well both with my test cases as well with your example: intervals

mmaxs commented 3 years ago

In this case just ceil may have a rounding problem that results in an extra point at the end.

Could you give an example? I don't see any issue with the formula 1 + ceil((max - min) / delta). Look, with your scheme now: i1 := [1, 2 .. 4.001] gives [1 2 3 4.001] -- missing of 4 (rounding effect by chance) i2 := [1, 2 .. 5.001] gives [1 2 3 4 5 5.001] -- OK (rounding effect by chance) i3 := [1, 2 .. 5.0001] gives [1 2 3 4 5.0001] -- missing of 5 (will always)


Screenshot_2020-12-12-17-04-43 b.interval3.mmt.zip

mkulesh commented 3 years ago

Hi @mmaxs, this is an example where 1 + ceil gives us more points than necessary: ceil

Now I used mode general approach. If you look into the document properties (menu "Document settings"), there is a parameter "Significant digits in result". I now used this parameter. The initial number of points N is now floor((max - min) / delta) . If the given maximum value is greater than (min + N delta) with respect to the precision defined by "Significant digits" parameter I will add this maximum value at the and. If the maximum value is equal to (min + N delta) with respect to this epsilon, no need to add this maximum. This approach solves both your initial and the last observation as well as satisfies all my automatic tests.

mmaxs commented 3 years ago

I think it is failry good solution. Don't you think that in the conditional operator (max > d1 && (max - d1) > eps * d1) ? N + 1 : N instead of (max - d1) > eps * d1 should be just (max - d1) > eps? I mean the following situation when by just changing the beginning of an interval, we get a different number of points: IMG_20201215_211558 In the second case, the observed end of the interval is actually 10002.81, and the penultimate point of the exact value of 10002.8 is missing.

mkulesh commented 3 years ago

Hi @mmaxs the use of the absolute deviation like (max - d1) > eps has a problem with small values like in this example: intervals1

If the absolute deviation (max - d1) > eps instead of relative (max - d1)/d1 > eps is used, both intervals will be shortened.

In your example it is enough to set "Significant digits" to 7 and you will have all points: interval2

mmaxs commented 3 years ago

this is an example where 1 + ceil gives us more points than necessary: ceil

But that interval with those parameters just should have 34 points. Any interval from min up to max with delta=(max - min)/N always has exactly N+1 points. And I see that in the ts_intervals.mmt tests the desired rows() value for it is M+1, that is 34.

So, for any user input for the interval in form of [min, min+delta, ..., max], it may be processed as point[0] = min point[1] = min + delta point[2] = min + 2 delta ... point[N] = min + N delta, where N = floor((max - min)/delta) and then, if point[N] < (max - epsilon), we must add one yet point[N+1] = max or else, if point[N] >= (max - epsilon), we, instead, should just set point[N] = max, as far as point[N] can't be > max due to the floor() function.

Another way to do all of that is point[0] = min point[1] = min + delta point[2] = min + 2 delta ... point[N] = min + N delta, where N = ceil((max - min)/delta) here, point[N] can't be < max due to the ceil() function (mathematically it can't, but in real calculations it can happen that it occurs to be < max, but in this case it's just a float point arithmetic effect), so we just always forcibly restrict (or fix) it to point[N] = max

mkulesh commented 3 years ago

Hi @mmaxs I totally agree with this theory. You are right, both approaches may be used and shall give perfect results. Your initial example b.interval1.mmt as well as all my other examples work with N=ceil((max - min)/delta) very well.

However, look at the test number 8 in ts_intervals.mmt again. It is a really special situation. dy = (y2-y1)/M = 5.9/33 is here a irrational number 0.1787878787878787... and it produces really huge numerical error when just ceil((max - min)/delta) is used: N = 34 point[0]=-3.0 point[1]=-2.8212121212121213... point[2]=-2.642424242424242... ... point[33]=2.899999999999997 point[34]=2.9 i.e we have 35 points and visually the result looks like this: interval3

Only this example and this test case is my problem. Mathematically it is correct, all 35 points are here, but due to numeric the last and previous points are equal. My idea was to skip the last point in this case and round up the previous point. I am sorry, in the screenshot 4 days ago I mistakable told about points number. In my code N is the index of the last point, i.e I have N+1 points. I mean here last index shall be 33 instead 34 with respect to this idea.

Of course we can say that my last really strange screenshot is a desired behavior and I just change adapt the test case accordingly. That do you think?

mmaxs commented 3 years ago

Now I have understood what you are talking about. I made some description of the problem: b.interval7.mmt.zip

mkulesh commented 3 years ago

Hi @mmaxs, Все верно, вы очень точно описали мою проблему. Мне тоже кажется, что самая последняя версия хорошо соответствует подходу номер 2. Я тоже теперь вижу, в чем проблема с (max - d1)/d1 > eps. Действительно, деление разностной величины (max - d1) на абсолютную d1 не есть хорошо. Если использовать формулу для абсолютной погрешности (max - d1) > eps, то результат будет так себе: interval Поэтому я уверен, что здесь нужно использовать относительную погрешность, а не абсолютную. И ваша идея (max - d1)/delta > eps мне очень понравилась, спасибо! Реализовал в последней версии именно этот вариант. Все мои тесты с этим вариантом работают хорошо. Тестируйте: https://github.com/mkulesh/microMathematics/raw/autobuild/autobuild/microMathematics-v2.21.0-debug.apk

Я хочу сегодня-завтра выпустить эту версию, так как в ней есть два очень важных исправления. Предлагаю этот тикет закрыть, так как изначальная проблема исправлена, дальнейшую дискуссию продолжить по почте, и окончательный вариант войдет в следующий релиз.

mmaxs commented 3 years ago

Thank you.

mkulesh commented 3 years ago

Released in version 2.21.0