-
-
Notifications
You must be signed in to change notification settings - Fork 122
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
round() macro in Arduino.h #76
Comments
In fact,
|
It violates the IEEE standard, making the Arduino floating point unpredictable. It is really a terrible bug. |
It should be a floating point calculation if
Some investigation is surely needed at this point, thanks for pointing it out and sorry for the previous response |
The round() function should return a floating point number. Some explanations for other platforms say that it returns the nearest integer, that might be confusing, but those functions still return a floating point. |
The thing is, Arduino is not standard C++, but some sort of language of its own that is based on C++ but introduces some simplifications. Among other things, it creates its own functions (well, macros) for Alternatively, if you want to use Now, some thoughts:
|
@cousteaulecommandant, I have to disagree with you. There is no good reason to change things for the bad. If you are right, then let's change ' Meanwhile I learned that the Java round function returns an integer instead of a floating point number of the nearest whole number. Most people seem to think of that as a mistake when the Java language was created. Since Arduino uses 'c' and 'c++' the |
Perhaps you are unaware of Arduino's long 12 year history? Not everything you take for granted as working perfectly well in the modern versions of avr-libc was always so reliable. |
In fact, (If anything, it's C++'s fault for defining a function that already existed in Arduino, not Arduino's fault for defining a function that already existed in C++.) |
The c math with the round function (with floating point parameter and floating point return) is at least C99 as far as I know. I hope you don't mind, but I stick with my strong words: "really ruins the math library". It's a matter of principle. The math library as a whole should be reliable. In my opinion it is not okay to mess around with standardized math functions. |
avr-libc still does not fully implement C99, and until only a few years ago it lacked many of the C99 functions it has today. Sticking to your strong words and accusatory tone isn't helping. |
I'm very sorry if my tone was accusatory. I didn't mean to be like that. I hope you agree with me that a lot of effort has been put into the math library, and the round function in the math library is perfectly fine. |
Well yes, but Arduino is based on C++, not C. In any case, it is true that it could be considered dropping the |
False. It is based on C and C++. |
The round() macro, as it is currently implemented by Arduino, also suffers from evaluating its arguments multiple times. For an explanation, see "More Gotchas" on this page: http://www.cprogramming.com/tutorial/cpreprocessor.html One possible fix might look like this:
But perhaps it would be best to just use the C library round(), now that it's fully supported by the modern AVR toolchain, and as far as I know all the 32 bit toolchains. |
Thank you PaulStoffregen. The origin of this issue is this: http://www.arduinoforum.nl/viewtopic.php?f=9&t=2454 As far as I know, in 'c' and 'c++' the round function returns a floating point number which is rounded to the nearest whole number. I really don't know any other way. I didn't know the history of this, but at this point it would be good to confirm with the standard round function. |
This may be stating the overly obvious, but around here arguments about novice user experience and backwards compatibility with the 12 year legacy of Arduino gain a lot more traction than promoting standards compliance, especially C99, C++11, etc. |
I'd rather use an actual function and end this macro madness: template<typename T> long Round(T x) {
return (x>=0) ? (long)(x+0.5) : (long)(x-0.5);
}
#define round(x) Round(x) // for backwards compatibility or simply #define round(x) lround(x) or do nothing at all, and use the standard |
@facchinm, I don't know what's going on but I got different results.
so the standard functions save more resources if the result is assigned to a long, but the "custom" ones are PS: Then again, if the result is going to be assigned to a float, it should not be intermediately cast to long because of the potential loss of range, so only math.h's |
@cousteaulecommandant Technically speaking this is false. That said, I completely support the stance that macros should be dropped in favour of the template approach (where possible). Macros should be avoided (where possible) because they have a great many downsides. "Then again, if the result is going to be assigned to a float, it should not be intermediately cast to long because of the potential loss of range, so only math.h's round does the right thing." I completely agree with this. If casting is going on, the user should be aware of it at all times. |
Since we migrate byte and boolean I think we should just use the standard c library with its round() implementation too. Same for the above linked abs() function. |
Is this still an issue? It seems that currently, no Not sure if this was really intentional, since the commits are big and the commit messages do not mention these changes at all. See e7cda3c where |
That is the ArduinoAPI.h |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Back to the original subject, @Koepel said:
I suspect you are looking at the AVR core? That is not yet based on this ArduinoCore-API repository, but as soon as it is converted, it should use code from this repo and the macro is, IIUC, gone in favor of using My original question about whether this is intentional or not still stands, though, since this change does have small compatibility implications, so it should be at least documented somewhere. |
The function round() in "math.h" is okay, it returns a floating point number as expected.
The macro round() in "Arduino.h" is a bug. It can not handle large floating point numbers and it returns a long integer.
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
It could be renamed to something else, for example ROUND_INT().
The sketch below shows the difference. With the normal round() function it returns four times "1.50", and with the round() macro in "Arduino.h" it returns: "1.00", "1.50", "1.50", "0.00".
The text was updated successfully, but these errors were encountered: