The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
I found a Log function for the MicroFramework a couple months ago, but it seemed to get stuck in an infinite loop so I thought the code was bad/untested, but then I happened to try a simplified version in the emulator tonight, it worked! The same exact code fails when running on the NetduinoPlus hardware. So, I took a close look into which line is at fault when running on the netduino and what I found is that the condition for the while loop returns true for this expression: 0.0 >= 4.94065645841247E-324. Causing an infinite loop.
Here is the screenshot and the code:
public class Program
{
public static void Main()
{
// Result for Log(7) should be 1.9459101490553133051053527434432
Debug.Print(Log(7, System.Math.E).ToString());
}
/// <summary>
/// Calculate logaritmic value from value with given base
/// </summary>
/// <param name="x">a Number</param>
/// <param name="newBase">Base to use</param>
/// <returns>Logaritmic of x</returns>
public static double Log(double x, double newBase)
{
// Based on Python sourcecode from:
// http://en.literateprograms.org/Logarithm_Function_%28Python%29
double partial = 0.5F;
double integer = 0F;
double fractional = 0.0F;
if (x == 0.0F) return double.NegativeInfinity;
if ((x < 1.0F) & (newBase < 1.0F)) throw new ArgumentOutOfRangeException("can't compute Log");
while (x < 1.0F)
{
integer -= 1F;
x *= newBase;
}
while (x >= newBase)
{
integer += 1F;
x /= newBase;
}
x *= x;
while (partial >= double.Epsilon)
{
if (x >= newBase)
{
fractional += partial;
x = x / newBase;
}
partial *= 0.5F;
x *= x;
}
return (integer + fractional);
}
}
So, as a workaround, I changed the last while loop line to this:
while (partial >= double.Epsilon && partial != 0.0)
And now it works, but I am baffled why it doesn't work as originally written. My concern is that there is a precision issue in here somewhere...
Thats a really small number... does it need to be that precise ?
A double is a double... They all have the same precision, so I would think the smallness of double.Epsilon should be fine. Also, this is a framework provided constant, not mine. I actually know very little about how log functions work. I push the magic button on the calculator and it works. Or I use Math.Log when coding. But in this case, all I've got is this code. I'm not too concerned with making the log function work since I can get it to give me the right value, but I would like to know why that comparison is giving me different results in hardware. I have many other comparisons in my code and I just want to understand, what's the difference?
Also, here is a simpler example:
double value = 0.0;
Debug.Print((value >= double.Epsilon).ToString());
The above code incorrectly returns true on the Netduino and false in the emulator.
Now, eliminate the variable:
Debug.Print((0.0 >= double.Epsilon).ToString());
The above code correctly returns false on both the Netduino and the emulator.
I think the only difference is one is a double to single comparison and the other is a double to double. Interesting...
Update: They are both double to double comparisons and even adding the "D" postfix does not change the results.
Yes, it is that important. There is an obvious bug here somewhere that should be fixed - who knows what else it might effect in the system.
Reminds me of Intel's FDIV bug in the early Pentium processors - Let's try to handle this bug's discovery a little better than Intel did.
Chris?
Trying to give anything that might help. I notice that Parse sets the Epsilon value to 0 both by hand and by giving it the value itself (in string form).
Parse works fine at 4.9406564584124647e-307 but as soon as you hit 4.9406564584124647e-308 the parse sets it to 0.
That is really interesting. I read a little about this epsilon stuff on wikipedia, and from what I read there, it looks like Epsilon for the double should be 1.11e-16, but it is 4.94065645841247E-324 in both regular and micro .NET Framework. So, I took the java code for calculation of Epsilon and ran it on my netduino and got an approximation of 2.2204460492503131e-16 which is close to the 1.11e-16 and no where near the double.Epsilon value of 4.94065645841247E-324. So now, I am wondering if I am just exceeding the precision of the hardware and the constant (double.Epsilon) is just plain wrong? When I go back and use 1.11e-16 as my epsilon, netduino returns the correct answer. But, from references online: double - 8 bytes IEEE 754. Covers a range from 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative).
So why is the calculated Epsilon so far off from the double.Epsilon constant?
Here is my conversion of the java code from wikipedia for determining an Epsilon approximation:
public static void Main()
{
// write your code here
calculateMachineEpsilonFloat();
calculateMachineEpsilonDouble();
}
private static void calculateMachineEpsilonFloat()
{
float machEps = 1.0f;
do {
machEps /= 2.0f;
}
while ((float)(1.0 + (machEps/2.0)) != 1.0);
Debug.Print( "Calculated Float Machine epsilon: " + machEps );
// Emulator and netduino float result: 1.1920929e-007
}
private static void calculateMachineEpsilonDouble()
{
var machEps = 1.0;
do
{
machEps /= 2.0;
}
while ((double)(1.0 + (machEps / 2.0)) != 1.0);
Debug.Print("Calculated Double Machine epsilon: " + machEps);
// Emulator and netduino double result: 2.2204460492503131e-16
}
So why is the calculated Epsilon so far off from the double.Epsilon constant?
Eureka! double.Epsilon is the wrong value to use for comparisions in C#. It is apparently a very poorly named constant. See the discussion here. So ultimately, the code is doing a comparison that is beyond the limit of precision (* I think *) when using double.Epsilon. So, the correct epsilon to be used in this case is.... 2.22045e-016
And that does seem to return a correct result. I guess if you use a smaller number, it's a crap shoot as to whether you'll get the correct answer...
My guess is that MS screwed up when they originally put that constant in the framework and decided that changing it could cause more harm than good, so they changed the definition instead.
it is 4.94065645841247E-324 in both regular and micro .NET Framework.
It seems Microsoft might have a history of this. Specifically in that last post from Microsoft:
We couldn't change the value of the current Double.Epsilon without breaking people who rely on it, and we aren't planning to add a new property for .NET Framework 4.0. But continuing to get votes and comments on this issue will help us prioritize this against other requests and potential features for the next release.
It's currently marked as resolved, but I don't much trust that at the moment.
Nice find, I had not seen those. So the final answer is --
Don't use double.Epsilon, use 2.22045e-16 instead.
I'm just happy no firmware update is needed to fix this and I don't have to worry about the netduino doing comparisons incorrectly.
It would be nice to start a collection of math functions. Maybe on codeplex. Perhaps I can ask Elze if he's ok with using his exMath.cs as the starting point.
Update: Elze never got back to me. Also, here is the final version of the Log function that I use today on my Netduino:
/// <summary>
/// Calculate logaritmic value from value with given base
/// </summary>
/// <param name="x">a Number</param>
/// <param name="newBase">Base to use</param>
/// <returns>Logaritmic of x</returns>
public static double Log(double x, double newBase)
{
// Based on Python sourcecode from:
// http://en.literateprograms.org/Logarithm_Function_%28Python%29
double partial = 0.5;
double integer = 0;
double fractional = 0.0;
double epsilon = 2.22045e-16;
if (x == 0.0) return double.NegativeInfinity;
if ((x < 1.0) & (newBase < 1.0)) throw new ArgumentOutOfRangeException("can't compute Log");
while (x < 1.0)
{
integer -= 1;
x *= newBase;
}
while (x >= newBase)
{
integer += 1;
x /= newBase;
}
x *= x;
while (partial >= epsilon)
{
if (x >= newBase)
{
fractional += partial;
x = x / newBase;
}
partial *= 0.5;
x *= x;
}
return (integer + fractional);
}
In case it helps someone, a temperature bead was added to my Netduino last night, and I needed a Log function. (using code from here) Valkyrie-MT your function worked perfectly. Where I struggled was with the base. I needed to use the Natural Logarithm base of 2.718281828 to get the right result, so:
Would you believe I answered this very question on Stack Overflow a couple of years ago?
It could be a whole lot worse - we live in a world were floating point implementations are so good and so complete and so ubiquitous that none of you has ever needed to read the IEEE specification (otherwise you would have known all about FP and epsilon values). That's a good thing.
The IEEE specification does not mention any epsilon, and as you've seen most people actually have less knowledge about floating points than they'd need - also there are severe misconceptions like
A double is a double... They all have the same precision
flying around ... leading to bugs like this
I believe that no discovery of fact, however trivial, can be wholly useless to the race, and that no trumpeting of falsehood, however virtuous in intent, can be anything but vicious.
-- H.L. Mencken, "What I Believe"