Making function next(), and back() for G'MIC.

I decided to go into CImg.h again, and made next().

Here it is:

C:\gmic-cli\CImg>gmic echo {next(3.2)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
3.2000000000000006
[gmic]./ End G'MIC interpreter.

C:\gmic-cli\CImg>gmic echo {next(nan)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
nan
[gmic]./ End G'MIC interpreter.

C:\gmic-cli\CImg>gmic echo {next([3.2,5])}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
3.2000000000000006,5.0000000000000009
[gmic]./ End G'MIC interpreter

next(n) generates the next representable number after n. So, it’s n+eps.

For back(n)

C:\gmic-cli\CImg>gmic echo {back(3.2)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
3.1999999999999997
[gmic]./ End G'MIC interpreter.

C:\gmic-cli\CImg>gmic echo {back(nan)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
nan
[gmic]./ End G'MIC interpreter.

C:\gmic-cli\CImg>gmic echo {back([3.2,5])}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
3.1999999999999997,4.9999999999999991
[gmic]./ End G'MIC interpreter.

So, would this be useful?

I was thinking about something similar last week, and my impression is that it could be way better to define a new pre-defined variable like eps that would be the minimal difference between two consecutive double values.
It is better, because :

  • Functions next(x) and previous(x) would be simply x+eps and x - eps, so that is straightforward.
  • You could use eps in other functions when necessary (otherwise you would have to do eps = next(x) - x which is a bit odd to define eps.
1 Like

Would it make sense to have both of these? I do like the idea of eps being automatically determined at run time and I think that’s more self-documenting.

I’m leaning to just eps if it is possible to do just that.

I’m not a big fan of adding new native functions in the math parser (in this case next() and previous()), if they are as simple to define as:

next(x) = (x + eps);
previous(x) = (x - eps);

These functions won’t be used in a lot of situations for sure, and having a native implementation in this case would not even be that faster (it just an addition/subtraction with a constant value).

I tested a use case with modulo using 2.2204460492503131e-16, and it seems better than using next().

C:\gmic-cli\CImg>gmic echo {259%(256+2.2204460492503131e-16)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
3
[gmic]./ End G'MIC interpreter.

C:\gmic-cli\CImg>gmic echo {259%next(256)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
2.9999999999999432
[gmic]./ End G'MIC interpreter.

I guess this can be concluded.

Though, I do think there may be some precision issue for very low/high value, like we see here:

C:\gmic-cli\CImg>gmic echo {9007199254740992+2.2204460492503131e-16}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
9007199254740992
[gmic]./ End G'MIC interpreter.
C:\gmic-cli\CImg>gmic echo {next(9007199254740992)}
[gmic]./ Start G'MIC interpreter (v.3.3.3).
9007199254740994
[gmic]./ End G'MIC interpreter.