Log in

View Full Version : remainder function


Ether
31-01-2013, 18:38
Does the C++ compiler used for FRC support the REMAINDER operator "x REM y" per IEC 60559

as specified on Page 235 Section 7.12.10.2 of ISO/IEC 9899:TC3 ?



If someone would be willing to test that with y=360

and x values of 179, 180, 181, 359, 721, -1, -179, -180, -359, -361, -721

and post results it would be much appreciated.

sur
31-01-2013, 22:48
It seems to be defined if you use the C compiler, but not the C++ one. You could use fmod (http://www.cplusplus.com/reference/cmath/fmod/), which has slightly different behavior.

You can test it out here: http://codepad.org/86MlmNXU

Ether
01-02-2013, 00:41
fmod(x,y) is quite different from remainder(x,y)

The 3 columns below are x, remainder(x,360), and fmod(360):


180.000 -180.000 180.000
181.000 -179.000 181.000
-181.000 179.000 -181.000
359.000 -1.000 359.000
-359.000 1.000 -359.000
719.000 -1.000 359.000
-719.000 1.000 -359.000

nightpool
01-02-2013, 09:18
What's the issue with using the modulus operator instead of the built-in remainder function?

Ether
01-02-2013, 09:24
What's the issue with using the modulus operator instead of the built-in remainder function?

Are you saying there is a remainder function in the C++ compiler used for FRC?

sur
01-02-2013, 11:54
It looks like you need to define it using extern "C" for WindRiver to compile it correctly:

#include <cmath>
using namespace std;

extern "C" double remainder(double, double);

Racer26
01-02-2013, 12:35
Are you saying there is a remainder function in the C++ compiler used for FRC?




There's definitely a modulus division operator, which amounts to the same thing.

719 % 360 = 359

nightpool
01-02-2013, 12:57
There's definitely a modulus division operator, which amounts to the same thing.

719 % 360 = 359

Right, but it rounds the same as fmod() (see http://www.gnu.org/software/libc/manual/html_node/Remainder-Functions.html). I don't have enough experience to say when this would be more or less useful in practice, but if you DO need it extern "C" seems to be the way to go about it.

Ether
01-02-2013, 13:01
There's definitely a modulus division operator, which amounts to the same thing.

719 % 360 = 359

The modulus division operator is *not* the same thing as the remainder function.

remainder(719,360) is -1, not 359.

Look at the definition of the remainder function which I attached to the original post in this thread.

Racer26
01-02-2013, 13:21
OK, so do this instead:


output = (719 % 360 > 180) ? (-360 + (719 % 360)) : (719 % 360);

Cal578
01-02-2013, 13:38
I can see how the remainder function would be useful in certain cases, except that I don't like the name of the function. It's non-intuitive, and the results would surprise many people who look at the code after the original writer. When I think back to when I learned division in elementary school, the remainder of two positive numbers was always positive (or zero). I'm trying to think of what I would have named that function, to be more in line with its return values.

nightpool
01-02-2013, 13:40
The "normal" name for this function is drem(), which I think is a contraction of d-something and remainder.

Ether
01-02-2013, 13:45
The "normal" name for this function is drem()

"Normal" according to whom? Link please.

Cal578
01-02-2013, 13:47
"Delta Remainder" sounds cool. At least when I see drem, I would expect slightly different behavior, thus obeying the programming law of Minimize Surprise.

nightpool
01-02-2013, 13:55
GNU libc. See the link in my previous post.

Ether
01-02-2013, 14:12
OK, so do this instead:


output = (719 % 360 > 180) ? (-360 + (719 % 360)) : (719 % 360);


Fails when angle = -359. Doesn't work with floats.

Ether
01-02-2013, 14:16
It looks like you need to define it using extern "C" for WindRiver to compile it correctly:

#include <cmath>
using namespace std;

extern "C" double remainder(double, double);

Would you mind running that and see if it produces the same output as this:

double myRemainder(double x, double y){
return x-y*floor(0.5+x/y);
}

Racer26
01-02-2013, 15:12
What about:


double EthersRemainder( double x, double y ){

int wholenumber;

wholenumber = (int)(x/y);

double result;

result = (x - (wholenumber * y));
if(result > 0.5*y) {
result -= y;
}

return result;

}

Ether
01-02-2013, 15:41
What about:
EthersRemainder


That's not my remainder.

Did you compile and run it ? It doesn't work correctly.

I'm sure that there's a way, with enough conditional logic, to torture fmod() or % into into a remainder* function, but what I am really asking in this thread is

a) does the C++ compiler provided with FRC have the remainder* function, and

b) does it behave like this:


*This* is my remainder:

double myRemainder(double x, double y){
return x-y*floor(0.5+x/y);
}


*per IEC 60559 as specified on Page 235 Section 7.12.10.2 of ISO/IEC 9899:TC3

Racer26
01-02-2013, 17:23
If you have a function that works, then use it?

I don't understand your qualm?

I have not ever encountered a programming scenario where modulus division didn't solve my desire for a remainder, so I'm a bit lost.

If there doesn't exist an operator that does what you want, then you need to either a) fabricate a solution from the operators you have access to, or b) find a library that does that for you.

Ether
01-02-2013, 18:16
If you have a function that works, then use it?

I do use it. But I don't want to be telling other people to use my custom function if there's already a perfectly good remainder function provided with FRC C++. I don't have access to a working C++ installation, otherwise I would test it myself. I am seeking help from knowledgeable C++ users on this forum.

I don't understand your qualm?

Honestly, that's because I don't have a qualm. I am perfectly calm.

I have not ever encountered a programming scenario where modulus division didn't solve my desire for a remainder, so I'm a bit lost.

I have encounted at least one such scenario, and that's why I posted this thread.

For example, the IEC60559 remainder function can take any angle and normalize it to the range -180..+180 with a single C instruction:

normalizedAngle = remainder(angle,360);

I'd like to know if the remainder function is supported in FRC C++ so I can recommend it to students who are trying to do this type of conversion.

Neither the fmod() function nor the % operator can replicate the functionality of the remainder() function without using a bunch of conditional logic

If there are any Java programmers following this thread, Java appears to have the IEC 60559 remainder function; in Java it is called IEEERemainder (http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Math.html#IEEEremainder%28double,%20double%29). See attachments. If someone would be willing to test that (compare it to the implementation I posted ealier in this thread) I'd be grateful.



qualm
/kwä(l)m/
Noun

1) An uneasy feeling of doubt, worry, or fear; a misgiving.
2) A momentary faint or sick feeling.

Synonyms
nausea - queasiness

omalleyj
01-02-2013, 19:06
In a Java SE project this

double result;
double x[] = {179, 180, 181, 359, 721, -1, -179, -180, -359, -361, -721};

for (int i = 0; i < x.length; i++){
result = Math.IEEEremainder(x[i],360.0);
System.out.println("x: " + x[i] + " rem y: 360 result: " + result);
}


yields this:

x: 179.0 rem y: 360 result: 179.0
x: 180.0 rem y: 360 result: 180.0
x: 181.0 rem y: 360 result: -179.0
x: 359.0 rem y: 360 result: -1.0
x: 721.0 rem y: 360 result: 1.0
x: -1.0 rem y: 360 result: -1.0
x: -179.0 rem y: 360 result: -179.0
x: -180.0 rem y: 360 result: -180.0
x: -359.0 rem y: 360 result: 1.0
x: -361.0 rem y: 360 result: -1.0
x: -721.0 rem y: 360 result: -1.0


which I believe is what you are looking for.

However I cannot use IEEERemainder() in an FRC project they have compiled the jar without it apparently.

Ether
01-02-2013, 20:23
In a Java SE project this

[snip]

yields this:

[snip]

which I believe is what you are looking for.

Excellent. Thank you! I'd give you some more reps, but it won't let me :(

However I cannot use IEEERemainder() in an FRC project they have compiled the jar without it apparently.

Not being a Java user, I'm not sure what that means. Is there a way to re-compile to include it, or is that a major undertaking?


Are there any C++ gurus out there who can look into the same question for C++ ?

Joe Ross
01-02-2013, 20:34
However I cannot use IEEERemainder() in an FRC project they have compiled the jar without it apparently.

That's not entirely true. FRC uses the Squawk JVM, which is based on Java ME. Java ME does not require IEEERemainder(), which is why it isn't in java.lang.Math. However, Squawk does implement some features from Java SE, and puts them in other packages. In this case, IEEERemainder is in the com.sun.squawk.util.MathUtils package.

omalleyj
01-02-2013, 20:39
Thanks!
Is there a cross reference of where SE stuff that's been moved can be found?

Ether
01-02-2013, 20:49
That's not entirely true. FRC uses the Squawk JVM, which is based on Java ME. Java ME does not require IEEERemainder(), which is why it isn't in java.lang.Math. However, Squawk does implement some features from Java SE, and puts them in other packages. In this case, IEEERemainder is in the com.sun.squawk.util.MathUtils package.

Joe, you never cease to amaze me :)

Joe Ross
01-02-2013, 21:54
Here's the result from the robot

double result;
double x[] = {179, 180, 181, 359, 721, -1, -179, -180, -359, -361, -721};

for (int i = 0; i < x.length; i++){
result = MathUtils.IEEEremainder(x[i],360.0);
System.out.println("x: " + x[i] + " rem y: 360 result: " + result);
}

[cRIO] x: 179.0 rem y: 360 result: 179.0
[cRIO] x: 180.0 rem y: 360 result: 180.0
[cRIO] x: 181.0 rem y: 360 result: -179.0
[cRIO] x: 359.0 rem y: 360 result: -1.0
[cRIO] x: 721.0 rem y: 360 result: 1.0
[cRIO] x: -1.0 rem y: 360 result: -1.0
[cRIO] x: -179.0 rem y: 360 result: -179.0
[cRIO] x: -180.0 rem y: 360 result: -180.0
[cRIO] x: -359.0 rem y: 360 result: 1.0
[cRIO] x: -361.0 rem y: 360 result: -1.0
[cRIO] x: -721.0 rem y: 360 result: -1.0

Joe Ross
01-02-2013, 21:55
Thanks!
Is there a cross reference of where SE stuff that's been moved can be found?

It's all in the javadocs, but I'm not aware of an easy cross reference.

Ether
01-02-2013, 22:17
Here's the result from the robot

Bingo! They match.

Radical Pi
02-02-2013, 02:16
From my installation, a grep through the headers folder shows no remainder functions. It's possible I'm missing something, but it looks like it doesn't exist at all in the vxWorks API.

As for the extern "C" option, yes that will make it compile, however the function will most likely not be resolved by the linker, which will cause problems when you try to run it. Wind River's system is designed to not complain about missing symbols until the cRIO's kernel tries to load the program. I'll check if this is the case tomorrow.

EDIT: actually, drem() does exist, and is defined to be the same as remainder() (see the glibc manual (http://www.gnu.org/software/libc/manual/html_node/Remainder-Functions.html)). However, the definition for it is in <private/trigP.h>, which isn't meant for inclusion by user programs. There don't seem to be any public headers which include it either.

Ether
02-02-2013, 10:06
drem() does exist, and is defined to be the same as remainder() (see the glibc manual (http://www.gnu.org/software/libc/manual/html_node/Remainder-Functions.html)).

Apparently in glibc, remainder() and drem() are two different names for the same function

Notice the very slight difference between the glibc and Java (http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Math.html#IEEEremainder%28double,%20double%29) definitions (handling of divide-by-zero).

nightpool
02-02-2013, 11:14
The "java" link you posted was to gnu libc...

Ether
02-02-2013, 11:27
The "java" link you posted was to gnu libc...

Fixed. Take a look.

Ether
08-02-2015, 16:56
Here's the result from the robot

double result;
double x[] = {179, 180, 181, 359, 721, -1, -179, -180, -359, -361, -721};

for (int i = 0; i < x.length; i++){
result = MathUtils.IEEEremainder(x[i],360.0);
System.out.println("x: " + x[i] + " rem y: 360 result: " + result);
}

Joe, is the MathUtils.IEEEremainder() method available in 2015 FRC Java, now that the runtime engine has changed? If so, does it produce the exact same results?

Joe Ross
08-02-2015, 17:32
Joe, is the MathUtils.IEEEremainder() method available in 2015 FRC Java, now that the runtime engine has changed? If so, does it produce the exact same results?




It's in Math, rather then the squawk MathUtils workaround, but it still works.

x: 179.0 rem y: 360 result: 179.0
x: 180.0 rem y: 360 result: 180.0
x: 181.0 rem y: 360 result: -179.0
x: 359.0 rem y: 360 result: -1.0
x: 721.0 rem y: 360 result: 1.0
x: -1.0 rem y: 360 result: -1.0
x: -179.0 rem y: 360 result: -179.0
x: -180.0 rem y: 360 result: -180.0
x: -359.0 rem y: 360 result: 1.0
x: -361.0 rem y: 360 result: -1.0
x: -721.0 rem y: 360 result: -1.0

Ether
08-02-2015, 19:00
It's in Math, rather then the squawk MathUtils workaround, but it still works.



Thanks Joe.

For those of you reading this thread for the first time, Math.IEEEremainder(angle,360.0) can be used to convert any angle (in degrees) to the range -180 to 180.

This can be very useful when working with the gyro.

Let's say you want to find the shortest angular error between your joystick direction angle and the gyro angle. This can be accomplished in one clean line of code as follows:

angle_error = Math.IEEEremainder(joystick-gyro,360.0);

There's no need for conditional logic. It cleanly handles all input angle ranges for joystick and gyro, including angles greater than 360 degrees and less than -360 degrees.

The above assumes that gyro and joystick share the same zero and measurement direction.