PDA

View Full Version : modf returns 1 instead of 0



qsurvae
11th July 2015, 02:59
This works




double myMin, mySec;

mySec = modf ( 0.44 * 100, &Min ); // returns desired result

// mySec = 0 , myMin = 44 -> this is correct




This doesn't work, I get incorrect result of myMin = 43 and MySec = 1




double myBearing = 172.4400;

testMyNum(myBearing);







void Delegate::testMyNum(double myDMS) const
{

double myMinSec, myDeg, myMin, mySec, multiply100;

multiply100 = 100;

myMinSec = modf ( myDMS, & myDeg );

mySec = modf ( myMinSec * multiply100, &myMin );

qDebug() << "myDeg " << myDeg << " myMin " << myMin << " mySec " << mySec;

// output -> myDeg 172 myMin 43 mySec 1 -> this is incorrect

}




How do I do this correctly in C++?

d_stranz
11th July 2015, 04:11
What's the value of myMinSec as it is being passed into modf()?

You are most likely suffering the consequences of the inexact representation of a floating point number in binary. 172.4400 is almost certainly not 172.4400000000000 (or how many digits it actually has) in binary. It's something very close to that but not exactly that.

If you want to do this exactly, convert your bearing to an integer:


int intBearing = int( myBearing * 10000 );
int myDeg = intBearing / 10000;
intBearing -= myDeg * 10000;
int myMin = intBearing / 100;
intBearing -= myMin * 100;
int mySec = intBearing;

(and if 0.4400 is actually a fraction of a degree, then I think you need some factors of 60 in there to get actual minutes and seconds).

qsurvae
11th July 2015, 05:31
What's the value of myMinSec as it is being passed into modf()?



The value of myMinSec is the fractional output of modf (172.4400, &myDeg), so the problem is as you describe.




If you want to do this exactly, convert your bearing to an integer:


int intBearing = int( myBearing * 10000 );
int myDeg = intBearing / 10000;
intBearing -= myDeg * 10000;
int myMin = intBearing / 100;
intBearing -= myMin * 100;
int mySec = intBearing;



Thank you I will try that.

*edit, unfortunately this doesn't work I will have to try something else.




(and if 0.4400 is actually a fraction of a degree, then I think you need some factors of 60 in there to get actual minutes and seconds).

This is just a snippet :)

Added after 38 minutes:

Another number issue.


QString myBearing = QString::number(172.4499);
qDebug() << myBearing;

output is "172.45"

How do I get "172.4499"?

ok RTFM :cool:

wysota
11th July 2015, 09:46
You need to understand that floating point data types are unable to represent each and every real number. They approximate values you give them to the nearest possible representation they might find. If you want to be sure no approximation is done, you need to use fixed point arithmetics.

ChrisW67
11th July 2015, 22:06
A variation of d_stranz's suggestion to work with integers and some care does work for your coded-decimal values:


#include <QCoreApplication>
#include <QDebug>
#include <cmath>

void bearingDecode(double myDMS)
{
bool negative(myDMS < 0.0);
myDMS = fabs(myDMS);
qint32 value = static_cast<qint32>(round(myDMS * 10000.0));
//qint32 value = static_cast<qint32>(myDMS * 10000.0); // to discard fractional "seconds"
qint8 mySec = value % 100;
qint8 myMin = (value / 100) % 100;
qint16 myDeg = value / 10000;
if (negative) myDeg = -myDeg;
qDebug() << "myDeg " << myDeg << " myMin " << myMin << " mySec " << mySec;
}


int main(int argc, char**argv)
{
QCoreApplication app(argc, argv);
QList<double> testValues;
testValues
<< 172.3999 << 172.4400 << 172.4401
<< 172.4499 // this one is out-of-bound for 'seconds'
<< 172.43999 // this one rounds
<< -172.2999; // don't forget negatives if needed
foreach(double testval, testValues) {
bearingDecode(testval);
}
return 0;
}

Outputs


myDeg 172 myMin 39 mySec 99
myDeg 172 myMin 44 mySec 0
myDeg 172 myMin 44 mySec 1
myDeg 172 myMin 44 mySec 99
myDeg 172 myMin 44 mySec 0
myDeg -172 myMin 29 mySec 99



Are you sure that 172.4400 represents 172°44'00" and not the more usual 172°26'24" ?

qsurvae
12th July 2015, 07:01
Thanks for the replies.

I understand the problem, I was after the c++ solution. The above solution may work, I didn't try it yet but I will keep it in mind. I found the easiest solution (for me) was to use strings.




error count: 0
1296000 of 1,296,000 results are correct!

d_stranz
12th July 2015, 17:31
This calls for a 11273

ChrisW67
12th July 2015, 22:12
I was not aware that I had slipped back into writing code in CORAL-66 (https://en.m.wikipedia.org/wiki/Coral_66)

d_stranz
14th July 2015, 20:16
My mistake. I thought it was SNOBOL (https://en.wikipedia.org/wiki/SNOBOL).