Repository navigation
Math isclose - #4894
Math isclose#4894stinos wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Until we fully switch to Python 3.5 as the reference, it'd be better to provide a .py.exp file for the test instead of this change.
There was a problem hiding this comment.
I think you can completely remove this check (at least the nan bits) and the logic below will catch these cases (I think).
There was a problem hiding this comment.
Good point, works for the nan cases indeed but not for inf because of the <= comparison
There was a problem hiding this comment.
To make it use less code these first two can be MP_QSTR_.
There was a problem hiding this comment.
It is possible to make constant float objects and point to them here, but that'll probably make the code bigger.
There was a problem hiding this comment.
They won't be static though so allowed_args also won't be static so the end result might be less performant.
There was a problem hiding this comment.
Since the default value of abs_tol is zero it can be {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}, and then always use mp_obj_get_float(...) to extract it below. This should save code size.
I agree. It's pretty straightforward and (like most math operations) only really one way to do it correctly.
I tend to agree, but I think this addition will be rather large (didn't test it yet). |
|
I pushed the Size of master (assuming the output after For this commit: When I apply the change where the default tolerance values are stored in constant objects the output is exactly the same. |
pfalcon
left a comment
There was a problem hiding this comment.
As any other additional feature added to (otherwise relatively self-sufficient) MicroPython, this should be conditional, default off.
What's the threshold for a genuinely useful feature? Just because it came later somehow makes it less valuable/important than something that came earlier? Just because we wrote a lot of Python without a given feature doesn't make that feature not useful. Conditional features are completely invisible to the vast majority of MicroPython users who aren't going to build their own firmware. It's the sort of thing that turns away new users. It makes the documentation confusing. I'd be keen to investigate some sort of "feature levels" so that conditional flags could be grouped together to provide a manageable set of build targets, but in the meantime these sort of comments on every PR that adds a new feature aren't very helpful. Everyone already knows that features (usually) comes at a space cost, and nobody wants to waste bytes, but features should be considered on their merits rather than a blanket ban. |
All various criteria were sounded many times. Here I'd suggest a following one: make a list of one thousand features you want to add to MicroPython. Of those, only one can be added. So, choose wisely. Don't make hasty choices. Collecting that list of 1000 features would alone take time, but still don't haste with that most important one. Wait half a year with it, hopefully it will wean off. If not, still wait a year to confirm it's really useful. This particular PR shows a good example of a feature which is hardly worth the bloat it adds on the C level (which affects everyone, whether they use it or not). What 99% people would need out of it is simple Python expression
I'm sorry, but I disagree. A typical emotion people seem to feel about MicroPython (without even properly realizing it) is something like: "What a small little cutie, we like it so much! Now, let's turn it into UGLY FAT MONSTER, because heck, we like it so much." I'm sorry, but if you need more features right away, just use CPython. Otherwise, just develop (and share, maintain, etc.) standalone modules in Python, because even CPython doesn't implement "everything" and you need external modules (and majority of CPython stdlib is developed in Python of course). |
|
Oops forgot to ask: is does this fall under 'special' functions i.e. should this be conditional with
Surely not everyone needs it, but I'm not too sure of that number. Or of the amount of people who can correctly estimate that epsilon to do the right thing for their case. |
But the talk started with pointing out that there's the established best practice that newly added stuff is made conditional. And if there's anything more to talk about it, it's a worrying fact that even long-time contributors ignore that best practice regularly. (Unless of course you think that math.isclose() is the crux of Python programming, in which case I'm happy to have countered that it's not.) |
Wasn't ignored here, rather intentionally done like that.. But it's a PR so if it's not to people's liking they can comment and it can still be added. |
You can't use CPython on a microcontroller, which is the primary aim of MicroPython. And, following (C)Python, MicroPython's aim is to be a useful language. There are other languages (eg Lua) which are minimal languages. Python is not a minimal language. And via the PEP process it was decided that |
This is not a good principle to go by because it leads to overly conditional code, too many configuration options, complete fragmentation of new features moving forward, and confusion as to what port supports what feature. And then the inability to use any new feature because it may not be there. Sure there has to be a considered balance of selecting new features to be included by default, but it doesn't make sense to be stuck always at what exists now. |
It's not really a special function, more like an extra/misc/aux function. There is already |
|
I have the same feeling but Paul doesn't so if we can decide what it's going to be I can adjust the code. How about |
|
Looking at code which should work the same across various builds and platforms, having build options for parts of a module like math is painful. Build options for complete modules are fine, espcially when it comes to save code size. |
There was a problem hiding this comment.
Since the default value of abs_tol is zero it can be {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}, and then always use mp_obj_get_float(...) to extract it below. This should save code size.
There was a problem hiding this comment.
If this goes before the isinf tests then it should be possible to test that either a or b are inf by a single call like isinf(difference), to save code size and make it more efficient for the more common case where inf is not passed in.
There was a problem hiding this comment.
There should be tests for the equality part of this inequality. Eg: math.isclose(0, 1, rel_tol=1), better still test_combinations(0, 1, rel_tol=1).
|
For the record the PEP is https://www.python.org/dev/peps/pep-0485/ |
|
I computed the size increase with this patch: That's quite a lot, so I suggest this new function be made optional via |
Enabled for the ports which already have MATH_SPECIAL_FUNCTIONS.
|
Ok addressed all comments |
|
Thanks! Merged in af5c998 with minor style edits, and additional tests for passing in negative numbers to |
Good catch, thanks! |
From previous discussion:
I honestly cannot tell, but I doubt it. What I did here is take code I already had for years in a personal project with several C++ utilities amongst which a couple of different ways of comparing floating point numbers, actual origin unknown, but comments say it's loosely based on Boost. This is one of those methods and I adapted it to work with MicroPython. I had a look at the current CPython implementation and it's pretty much exactly the same as this one. Which isn't a surprise because there's not that many ways to do this particular comparison [*], and the CPython code also mentions it looks like Boost's. However I didn't find a similar piece of code in (the current version of) Boost so hard to tell how it was extracted exactly.
[*] one alternative implementation here would be to first check if absolute value of a or b is the largest and then do the multiplication with rel_tol only once, instead of (possibly) twice now. Could be faster in general, didn't test that.
Was reluctant to do that because that lacks direct floating point support, but had a go at it now.
I did not make this feature conditional in the build as it just seems too important, but that might be me.
The implementation for complex numbers is going to look very similar I guess, but I'm not sure if we want to copy this one and adjust or make this one suitable for both with macros or function pointers or something similar.