TheSwamp

Code Red => .NET => Topic started by: Bryco on May 10, 2007, 10:57:42 PM

Title: Fuzz and doubles.
Post by: Bryco on May 10, 2007, 10:57:42 PM
I couldn't find this on this board, but coming from vba I use it all the time.
Is it a concern?
If so has anyone got the ulps method to work?
I would say my main reason to need it is to test a value against zero or pi.
Title: Re: Fuzz and doubles.
Post by: Kerry on May 10, 2007, 11:57:55 PM
OK, I'll play ..

Whats the ulps Method ?

Title: Re: Fuzz and doubles.
Post by: LE on May 11, 2007, 12:03:07 AM
I couldn't find this on this board, but coming from vba I use it all the time.
Is it a concern?
If so has anyone got the ulps method to work?
I would say my main reason to need it is to test a value against zero or pi.

Do a combination of Math.Abs(num2 - num1) <= fuzz [where fuzz is Double fuzz = 0.0001 or whatever] unless there is some built-in function in C#, that I have no idea.
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 12:08:27 AM
Well this was something that can't be done in vba but apparantly works fine in the C's.
The post isn't exactly how it was posted as I've messed with it trying to get a big enough integer.

Well if there is a way I don't need it I won't bother playing with it. I just dont know.

Code: [Select]
'Reading           http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm


'Paul Marshall http://www.cadvault.com/forums/showthread.php?t=15869&page=4&pp=10
Public Function IsEqual(ByVal a As Single, ByVal B As Single, maxUlps As Long) As Boolean
    ' Make sure maxUlps is non-negative and small enough that the
    ' default NAN won't compare as equal to anything.
    'maxUlps = 5  'I use this
    If Not (maxUlps > 0 And maxUlps < 4& * 1024 * 1024) Then
        Debug.Print "maxUlps out of range"
        Stop
    End If
    Dim aInt As Long 'originally integer
    CopyMemory aInt, a, 4
    ' Make aInt lexicographically ordered as a twos-complement int
    If aInt < 0 Then
        aInt = &H80000000 - aInt
    End If
    ' Make bInt lexicographically ordered as a twos-complement int
    Dim bInt As Long 'originally integer
    CopyMemory bInt, B, 4
    If bInt < 0 Then
        bInt = &H80000000 - bInt
    End If
    ' We need the range of an unsigned Long but
    '   there are no unsigned types available in VB
    '   (other than Byte).
    Dim intDiff As Currency
    intDiff = Abs(CCur(aInt) - bInt)
    Debug.Print a, "Long      " & aInt, bInt, intDiff
    If intDiff <= maxUlps Then
        IsEqual = True
    Else
        IsEqual = False
    End If
End Function
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 12:11:17 AM
Le that's what I do in vba and it works fine for me as I work in small numbers. But ulps seem to give a well rounded solution.
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 12:16:51 AM
ahhh ...

 Ulps ~= Units in the Last Place
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 12:31:12 AM
It looks nice, even the percentage comparison looks better that the basic test that I use. I don't know if it works for doubles as they show floats, I just spent 5 minutes trying to find what was wrong with something that I knew was correct to find out that "If" (the one I've been typing for years ) doesn't work but "if" does. Ahhhhhhh! Any way I'll test the code out for doubles some time before xmas.
Title: Re: Fuzz and doubles.
Post by: Glenn R on May 11, 2007, 01:33:28 AM
I just spent 5 minutes trying to find what was wrong with something that I knew was correct to find out that "If" (the one I've been typing for years ) doesn't work but "if" does. Ahhhhhhh!

Hehe...welcome to the beautifull world of case based languages. Once you get used to it, you'll never go back...trust me  :evil:
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 01:42:29 AM
Bryce, confirming the case fun ... though didn't the VB IDE take over and change case for you ??

I still regularly put a parenthesis in front of the (if ....
and just as regularly type ;; instead of // for a comment ... sometimes I think that some of the synapses are welded shut.  :|
Title: Re: Fuzz and doubles.
Post by: It's Alive! on May 11, 2007, 02:16:21 AM
I still regularly put a parenthesis in front of the (if ....
and just as regularly type ;; instead of // for a comment ...

Oh man, I do this too
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 08:08:37 AM
Bryce, confirming the case fun ... though didn't the VB IDE take over and change case for you ??

I still regularly put a parenthesis in front of the (if ....
and just as regularly type ;; instead of // for a comment ... sometimes I think that some of the synapses are welded shut.  :|

I frequently catch myself putting commas between function arguments in lisp code.

We need one syntax to rule them all. :-)
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 09:48:23 AM
Hehe, I'm glad that it's not just me.
Kerry the vbaide forces the capital I in If,

actually I had just copied
Code: [Select]
Function Rd(num1 As Variant, num2 As Variant) As Boolean
    Dim dRet As Double
    dRet = num1 - num2
    If Abs(dRet) < 0.00000001 Then Rd = True
End Function
to C# thinking that nothing could be easier.
(Morphs into Hatch for a minute)
Oops no boolean in help, ok got it bool.
Abs, no no help on that. Ah add using system.Math.Abs
Oh, better not call this class Math then, changes it to MyMath.
public static bool Rd(double num1,double num2), why is the )lighting up? static public bool Rd, nope still red (Wonders if it the order makes any difference)
static bool Rd, still red static void. Oh need to put the bracket thing on the next line. (It lights up the ")" as it's wrong in the future, as in the next line)
Code: [Select]
    public static bool Rd(double num1,double num2)
    {
        double dRet = num1 - num2;
        bool B=false;
        If (math.Abs(dRet) < 0.00000001)
        {
          B= true;
        }
        else
        {
            B= false;
        }
        return B;
    }
It's red on the if line, staring at for 5 mins with hatred does little to fix it,finally If.
This is when I posted to make sure I even need this function.
I've still got to figure out the top line
double num1,double num2 needs to be maybe object num1,object num2? as it is not always a double being fed to the function.
Right now $250 for the standard edition sounds like a cheap investment to take some of the agro out of learning this program.
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 12:23:23 PM
What are you using for an IDE?  C# syntax typically has the "if" in all lower-case letters.

Typically, I don't use a special function for this.  I will just include a line like the following right where it belongs in the code:

Code: [Select]
if (Math.Abs(num1 - num2) < fuzz)
{
    [other code...]
}

...where "fuzz" is a global constant.  This is straight-forward, simple, and easy-to-read.  If I saw a code with an "Rd()" function, that would constantly throw me, because my mind would want to interpret it as Round().

If you want to make one function that can handle different types, you would probably just want to overload the method, rather than use type "object".  This is easier to code, easier to read, and has less run-time overhead than one method that tries to handle multiple types.
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 01:24:22 PM
Sinc that sounds like the GO, (if I can figure out the global part.)
Yes the C# ide is awesome, I just copied in this code in and the If stays as it is.
Kerry's comment about learn C# language first then learn how to use it with cad is of course spot on.
But, but, but. (Grosshopper learn to love the pain.)
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 04:21:10 PM
There are a number of ways to do the global thing.  I'm not really sure of the best way in C#.  Maybe someone with more C# experience can chime in.

In the past, I've usually used #define directives to define a variable in the compiler.

But lately with C#, I've been using a "container class" and static variables to hold my global defaults, as in the attached sample.  For example, assuming the attached sample is a class in my project, I might access the NOD key for my application's standard Named Object Dictionary using something like this:

         Database db = Application.DocumentManager.MdiActiveDocument.Database;
         using (Transaction tr = db.TransactionManager.StartTransaction()) {
            DBDictionary NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
            DBDictionary spDict;
            try {
               spDict = (DBDictionary)tr.GetObject(NOD.GetAt(SincpacDefaults.ApplicationNODKey), OpenMode.ForRead);
            }
         }

The benefit to this last way is that I can change the global defaults without affecting any other code.  This is more of a benefit if you have a larger project, and compile the code into multiple DLLs.  If you ever change any of your defaults, you only need to recompile the DLL that contains this class, and all other code remains unaffected.  With a compiler directive you would need to recompile everything if it changed.  I might be overthinking this, but it seems to work well.

Code: [Select]
/*
 * Created by SharpDevelop.
 * User: Sinc
 * Date: 4/6/2007
 * Time: 9:35 PM
 */

using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AECC.Interop.Land;
using Civil3DUtilities;

namespace Sincpac
{
/// <summary>
/// Description of SincpacDefaults.
/// </summary>
public class SincpacDefaults
{
// Name of subsection for storing Global values
private const string globalRegistryKeyName = "Sincpac";

// Similar to above; contains the name of the dictionary in the NOD
private const string applicationNODKey = "SINCPAC-C3D";

public static string GlobalRegistryKeyName
{
get { return globalRegistryKeyName; }
}

public static string ApplicationNODKey
{
get { return applicationNODKey; }
}
}
}
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 05:00:49 PM
Beauty, I'll play with that on the weekend.
Thanks.
Title: Re: Fuzz and doubles.
Post by: MickD on May 11, 2007, 07:28:57 PM
Been a while since I've used c# but a static class variable/property is the most simple way to store a global 'like' value, for instance you could create a class called Utils which has a static property called fuzz which could be used like -

if(value >= Utils.fuzz()) //some comparison
{
    blah;
}

your property would look 'something' like

// the class property
static double fuzz()
{
    get
    {
        return myfuzz; //which is stored as a private variable in this class
    }
}

hth
Title: Re: Fuzz and doubles.
Post by: Bryco on May 11, 2007, 07:59:17 PM
Great, I'll give it a go this weekend.
5pm here, the amber liguid is calling something wicked.
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 08:10:16 PM
I think MickD just gave the exact same answer I did.   :-)
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 08:29:09 PM
Can I say "it depends" ??

I'd be just as happy doing the test in-line as Sinc's Reply#12

... except use an exponent ... easy for my old brain; if the exponent is -8 thats 8 significant places, no need to count zero's .. and the test criteria is immediately transparent.

I'd like a buck for every time I've shot myself in the foot trying to be too smart.

This seems pretty transparent :-
Code: [Select]
    public class FuzzyTester
    {
        [CommandMethod("CmdFuzz")]
        static public void CmdFuzz()
        {
            double num1 = 10.00000001;
            //double num2 = 10.00000002;
            double num2 = 10.00000005;

            if (Math.Abs(num1 - num2) < 1.0e-8)
            {
                MessageBox.Show("Bingo !", "My Fuzzy Interpreter",
                     MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else           
            {
                MessageBox.Show("Pffffft !", "My Fuzzy Interpreter",
                     MessageBoxButtons.OK, MessageBoxIcon.Warning); 
            }
        } 
    }



Bryco, Just a note on this ;

bool B=false;

You do not need to initialise the Value to false.
The process of declaring the variable
ie:
bool B;

will initialise the variable to false by default.

Similarly ;
int num;
will initialise num to 0 [zero]

Have a good weekend :-)
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 08:40:15 PM
AND .. just in case anyone watching is wondering why a fuzz factor is necessary sometimes ;

A Piccy !

Title: Re: Fuzz and doubles.
Post by: MickD on May 11, 2007, 08:50:07 PM
I think MickD just gave the exact same answer I did.   :-)

Yes you're right, I think I did and my appologies, it was just my eyes glazed over scanning your post when you were looking into NOD's and such and I got lost :laugh:
Title: Re: Fuzz and doubles.
Post by: LE on May 11, 2007, 08:55:42 PM
porting one of my c++ functions just to add more salsa to the tacos.
Code: [Select]
static bool eqDoubles(double i1, double i2, double ftol)
{
    double nom, denom, error;
    nom = Math.Abs(i1 - i2);
    denom = Math.Abs(i1) + Math.Abs(i2);
    if (denom != 0)
    {
        error = 2 * nom / denom;
        return (error <= ftol);
    }
    return true;
}

Code: [Select]
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;

Double num1 = 10.00000001;
Double num2 = 10.00000005;

if (eqDoubles(num1, num2, 1.0e-8))
    ed.WriteMessage("\n[They are Equal]");
else
    ed.WriteMessage("\n[They are Not Equal]");
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 09:00:15 PM
I s'pose another debate is
should it be

if (Math.Abs(num1 - num2) < 1.0e-8)

or

if (Math.Abs(num1 - num2) <= 1.0e-8)
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 09:01:36 PM
I think MickD just gave the exact same answer I did.   :-)

Yes you're right, I think I did and my appologies, it was just my eyes glazed over scanning your post when you were looking into NOD's and such and I got lost :laugh:

Yeah, that might've muddled up the matter.  But it was an example that I happened to have on-hand.  And it's actually a particularly useful example - the NOD is the primary way to store application-specific data in the drawing with C#.  So if you want each drawing to remember the last command settings, even when you shut down Autocad and restart it, the NOD is the way to go.

Just an extra tidbit for Bryco to chew on this weekend, while I do some experimenting myself with ImpCurves...   :laugh:
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 09:03:19 PM
I s'pose another debate is
should it be

if (Math.Abs(num1 - num2) < 1.0e-8)

or

if (Math.Abs(num1 - num2) <= 1.0e-8)


Is one any faster than the other?
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 09:03:24 PM
Bryco, Just a note on this ;

bool B=false;

You do not need to initialise the Value to false.
The process of declaring the variable
ie:
bool B;

will initialise the variable to false by default.

Similarly ;
int num;
will initialise num to 0 [zero]

Have a good weekend :-)


I was going to ask if that behavior is documented, but then I thought "why not look it up for yourself?"  I did, and it is.  Somehow it still just feels wrong to me, but thanks for the tip.
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 09:04:50 PM
I tend to do stuff like that explicitly anyway, for clarity of code.

The compiler makes it the same at runtime.
Title: Re: Fuzz and doubles.
Post by: sinc on May 11, 2007, 09:07:01 PM
I tend to do stuff like that explicitly anyway, for clarity of code.

The compiler makes it the same at runtime.

Oh, wait, maybe it doesn't...

It would be the same for optimized C code, but I actually have no idea what happens in C#...
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 09:13:56 PM
I tend to do stuff like that explicitly anyway, for clarity of code.

The compiler makes it the same at runtime.

Oh, wait, maybe it doesn't...

It would be the same for optimized C code, but I actually have no idea what happens in C#...

Maybe I'll play around with Reflector and see if there are any differences in the IL.
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 09:23:50 PM
Hmm.  Declaring an int without initializing it ( int i; ) causes a compiler error in VC# 2005 Express on my machine.  The error is "Use of unassigned local variable 'i'."

Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 09:36:47 PM
MSVS2005 compiles and runs it Chuck. Weird, heh ? 

Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 09:40:27 PM
MSVS2005 compiles and runs it Chuck. Weird, heh ? 

I haven't applied the service pack.  I suppose that could explain it.
Title: Re: Fuzz and doubles.
Post by: LE on May 11, 2007, 09:41:33 PM
I s'pose another debate is
should it be

if (Math.Abs(num1 - num2) < 1.0e-8)

or

if (Math.Abs(num1 - num2) <= 1.0e-8)


I also study the page Bryco linked in one of his posts (some moooons ago), before I was using (and still in some of my c++ routines)

Code: [Select]
#define EPS 1e-05
#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
#define EQN(x,y) (Absolute((x) - (y)) <= EPS)
#define EQNPLUS(x, y)(EQN(x,y) || x > y)
#define EQNMINUS(x,y)(EQN(x,y) || x < y)
// For checking near equal floating-point values
#define EPSILON 0.001 //0.0000000001 //0.0001   // tolerance.
#define DOUBLE_EQ(x,v) (((v - EPSILON) < x) && (x <( v + EPSILON)))

Then after all the reading in here:

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

Code: [Select]
static bool eqDoubles(double i1, double i2, double ftol)
{
double nom, denom, error;
nom = fabs(i1 - i2);
denom = fabs(i1) + fabs(i2);
if (denom != 0)
{
error = 2* nom / denom;
return (error <= ftol);
}
return TRUE;
}

That by simple changing fabs for Math.Abs and TRUE for true to be ported to C#
Title: Re: Fuzz and doubles.
Post by: LE on May 11, 2007, 09:49:55 PM
Hmm.  Declaring an int without initializing it ( int i; ) causes a compiler error in VC# 2005 Express on my machine.  The error is "Use of unassigned local variable 'i'."

using VS2005 pro.... and gets compiled.
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 09:53:59 PM
Here is an excerpt from the documentation for the error I receive.

Quote
The C# compiler does not allow the use of uninitialized variables. If the compiler detects the use of a variable that might not have been initialized, it generates CS0165.
Title: Re: Fuzz and doubles.
Post by: LE on May 11, 2007, 10:00:11 PM
Chuck;

I never had the chance to use the express version... but can you change the warning level? to 4 and see if works... maybe...
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 10:02:16 PM
Chuck;

I never had the chance to use the express version... but can you change the warning level? to 4 and see if works... maybe...

The warning level defaults to 4.  I changed it to 0 (and made sure 'report warnings as errors' was turned off), but it didn't make any difference.  Results are the same in Debug mode and Release mode.
Title: Re: Fuzz and doubles.
Post by: LE on May 11, 2007, 10:14:03 PM
this is what I have on mine... see if helps :)
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 10:20:10 PM
AHHHHH ...

I see the misunderstanding ..

The Variable can be declared without initializing

but must be subsequently assigned to before it can be used.

In Bryco's original code the initial assignment of false to B was not needed ... as I mentioned.

The subsequent assignment in the if conditional block satisfies the compiler specifications.

I should have been more explicit.



code added :

so the code block could change to ;
 
Code: [Select]
   public static bool FuzzyStuff(double num1,double num2)
    {
            bool B;       
           // bla bla ..
            B = (Math.Abs(num1 - num2) < 1.0e-8);
            return B;
     }

or simply
 
Code: [Select]
   public static bool FuzzyStuff(double num1,double num2)
    {
             return (Math.Abs(num1 - num2) < 1.0e-8);
    }
Title: Re: Fuzz and doubles.
Post by: Chuck Gabriel on May 11, 2007, 10:38:09 PM
Aha.  Thanks for clearing that up for me Kerry.
Title: Re: Fuzz and doubles.
Post by: Kerry on May 11, 2007, 10:51:02 PM
You're welcome.

My mess, had to clean it up  :|

Just noticed your next post is No. 1000 .. Make the most of it :-)
Title: Re: Fuzz and doubles.
Post by: Bryco on May 13, 2007, 04:30:36 PM
Thank's for the help all.
I like the inline method as it makes debugging easier (If I ever figure out how to do that)
but I needed to know how to work with globals anyway.

The ulps stuff I'm not to sure about.
I've played with it a bit more and so far I'm not sure that it is needed.
(Of course  this may not be corrrect)
Code: [Select]
namespace And1
{
using System;
using System.Windows.Forms;
using System.Diagnostics;


    public class Chere
    {

         static int Main()
        {   
            const int aa = 1;
            float b ;
            float a ;
            for (int i = -48; i <= 10; i++)
            {
                a = (float)Math.Pow(10, i);
                b = a+aa ;
                 Console.WriteLine(i);
                isEqual(a, b, 5);               
            }
             // These are here to show the numbers print like the article.
            //b = 4.2038954e-045f;       //3
            //a = 1.4012985e-045f;       //1
            //isEqual(a, b, 5);

            //b = 1.99999976f; //1073741822
            //a = 2.00000000f;  //1073741824
            //isEqual(a, b, 1);

            return 0;
        }

     
        unsafe static int Pointer(float Fl)
        {
            int i=*(int*)&Fl;
            return i;
        }

       static bool isEqual(float A, float B, int maxUlps)
        {   
           //Comparison showing the usual method

            Console.WriteLine("A-B:{0}-{1}={2} ans={3}",A,B,Math.Abs(A - B),  Math.Abs(A - B) <0.1e-10);
     
            Debug.Assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);

            //int aInt = *(int*)&A;
            int aInt = Pointer(A);

            // Make aInt lexicographically ordered as a twos-complement int

            if (aInt < 0)
            {
                aInt = (int)(0x80000000 - aInt);
            }
 
            int bInt = Pointer(B);
            if (bInt < 0)
            {
                bInt = (int)(0x80000000 - bInt);
            }
            int intDiff =Math.Abs(aInt - bInt);
           
            Console.WriteLine("Ulps: {0}-{1}={2} ans={3}", aInt,bInt,intDiff, intDiff <= maxUlps);
            if (intDiff <= maxUlps)

                return true;

            return false;

        }

    }
}
In build you need to check unsafe code.(Sounding pretty dubious already,eh!)

Here's a screen shot
Quote
A-B:100000-100001=1 ans=False
Ulps: 1203982336-1203982464=128 ans=False
6
A-B:1000000-1000001=1 ans=False
Ulps: 1232348160-1232348176=16 ans=False
7
A-B:1E+07-1E+07=1 ans=False
Ulps: 1259902592-1259902593=1 ans=True
8
A-B:1E+08-1E+08=0 ans=True
Ulps: 1287568416-1287568416=0 ans=True
9
A-B:1E+09-1E+09=0 ans=True
Ulps: 1315859240-1315859240=0 ans=True
10
A-B:1E+10-1E+10=0 ans=True
Ulps: 1343554297-1343554297=0 ans=True

What we have at 8 is both the Ulps and standard version reading true.
So at 9 digits the 1 in 1.000000001 (this doesn't happen with a double at this precision) automagically changes to a zero. So the need for ulps seems less important.
Going the other way (closer to zero)  by setting const float aa = 1e-40f; you'll see 5 ulps are way to accurate.
Title: Re: Fuzz and doubles.
Post by: TonyT on May 13, 2007, 06:21:41 PM
Well this was something that can't be done in vba but apparantly works fine in the C's.
The post isn't exactly how it was posted as I've messed with it trying to get a big enough integer.
<snip>

I'll take it from this, that you've not yet discovered Int64 ?

Title: Re: Fuzz and doubles.
Post by: Bryco on May 13, 2007, 06:31:53 PM
Not in vba Tony,
I see them in C# and the article recommended using them for doubles instaed of the 32 ints for floats.
Title: Re: Fuzz and doubles.
Post by: TonyT on May 13, 2007, 08:15:01 PM
Hehe, I'm glad that it's not just me.
Kerry the vbaide forces the capital I in If,

actually I had just copied
Code: [Select]
Function Rd(num1 As Variant, num2 As Variant) As Boolean
    Dim dRet As Double
    dRet = num1 - num2
    If Abs(dRet) < 0.00000001 Then Rd = True
End Function
to C# thinking that nothing could be easier.
(Morphs into Hatch for a minute)
Oops no boolean in help, ok got it bool.
Abs, no no help on that. Ah add using system.Math.Abs
Oh, better not call this class Math then, changes it to MyMath.
public static bool Rd(double num1,double num2), why is the )lighting up? static public bool Rd, nope still red (Wonders if it the order makes any difference)
static bool Rd, still red static void. Oh need to put the bracket thing on the next line. (It lights up the ")" as it's wrong in the future, as in the next line)
Code: [Select]
    public static bool Rd(double num1,double num2)
    {
        double dRet = num1 - num2;
        bool B=false;
        If (math.Abs(dRet) < 0.00000001)
        {
          B= true;
        }
        else
        {
            B= false;
        }
        return B;
    }
It's red on the if line, staring at for 5 mins with hatred does little to fix it,finally If.
This is when I posted to make sure I even need this function.
I've still got to figure out the top line
double num1,double num2 needs to be maybe object num1,object num2? as it is not always a double being fed to the function.
Right now $250 for the standard edition sounds like a cheap investment to take some of the agro out of learning this program.


Quote
I've still got to figure out the top line double num1,double num2 needs to be maybe
object num1,object num2? as it is not always a double being fed to the function.

Well, I think one thing you still haven't figured out, is the fact
that there's significant differences beween VB6/VBA and C#
and VB.NET.  The advice I generally give to someone coming
from VB6/VBA is to try to forget much of what they know
about those languages, and start over.

An example of where you're making the mistake of trying to apply
VB6/VBA concepts to C# programming, is to type parameters as
'object' to allow one of several different types to be passed.

In OOP langauges that support overloading, we don't do that.

Instead, we overload a function/method to accept what types
we want to allow it to accept.

So, what is 'overloading' ?

Code: [Select]

   public static class MyComparer
   {
      public static bool Equals( int x, int y )
      {
         return x == y;
      }

      public static bool Equals( double x, double y )
      {
         return Math.Abs( x - y ) < fuzz;
      }

      public static bool Equals( float x, float y )
      {
         return Math.Abs( x - y ) < fuzz;
      }

      public static bool Equals( Decimal x, Decimal y )
      {
         return Math.Abs( x - y ) < fuzz;
      }

      public static double fuzz = Double.Epsilon;

   }


Notice that the above class has four methods, all of
which have the same name. So, how can that be?
If you can declare more than one method with the
same name, how does the compiler know which you
mean?  The answer is simple, each of the methods
have the same name and number of arguments, but
each accepts different types as their arguments.

The compiler knows which method to actually use
based on what types you pass in a call to it. So, if
you pass the Equals() method two doubles, it will
call the version that takes two doubles as params.

Overloading is used in place of using 'object' as the
type, because you do not have to resolve the
type at runtime (e.g., test it to see if it is one of
the types you can accept, and reject it otherwise).
Using 'object' as a parameter prevents compile-time
type checking/enforcement, which means that you
must instead do that at runtime, which on a large
scale, slows down code immensely. Just ask any
LISP programmer :-D

You may also be wondering why the bodies of three
of those functions are identical. Well, in fact they're
not, and that's because the Math.Abs() function is
also overloaded, and each of the 3 functions above
calls a different overloaded version of Abs().

When you type 'Math.Abs(' in the IDE, notice that
the intellisense tooltip kicks in and and displays
'1 of 7' with up/down arrows. If you use the down-
arrow key you can scroll through the overloaded
versions of the function, and see the parameters
they take.

Another comment is that you're not really writing
proper code when you do something like this:

Code: [Select]
   

    public static bool Rd(double num1,double num2)
    {
        double dRet = num1 - num2;
        bool B=false;
        If (math.Abs(dRet) < 0.00000001)
        {
          B= true;
        }
        else
        {
            B= false;
        }
        return B;
    }


The entire function is pointless because it is
no different than:

   public bool rd(double a, double b)
   {
       return Math.Abs(a - b) < 0.00000001;
   }

No variable to hold the result. No if/then/else.

And, as others have noted, the need to have
a function that encapsulates just a few very
simple operations, is questionable.

So I think your use of the variable 'B' seems
to suggest to me that you're still thinking about
code in terms of VB6/VBA, where you must
assign the result of a function to its name.

An even more basic misunderstanding is that
you do not use if/then/else to translate a
boolean to a boolean.

In other words,

Code: [Select]

    bool val;
   
    if( test )
        val = true;
    else
        val = false;


Because, that is no different than:

Code: [Select]

    bool val = test;


In C#, you can just use 'return <value>' to return
a value from a function. There is no need to assign
the result of the function to a variable.

Lastly, in C# or VB.NET, there is no such thing
as a 'global' variable. There are only types and
members (static and non-static). In the example
class above, there is a static variable called 'fuzz'
which can be used like a global variable, by simply
prepending the class name to it, like this:

Code: [Select]

     MyComparer.fuzz = 1.0e-10;


You use static members of classes the same
way you use global variables in VB6/VBA. I
used a simple variable here rather than a
property, so as to not drag the concept of
encapsulation into the mess, which would
only serve to confuse that with the more
basic concept of scope, but in real world
development, the above variable might be
a property with a setter/getter.
Title: Re: Fuzz and doubles.
Post by: Bryco on May 13, 2007, 11:10:28 PM
That, Tony, is a really well written piece.
sinc mentioned overloading and I started looking at it but you've made it easy to figure out.
I have been trying the object way and so far haven't been successful.
Besides being a bad way to do it, it also seems a bit dodgy in that you may be getting a copy. Boxing is interesting but not easy to actually use.
The overloading is the GO.
Title: Re: Fuzz and doubles.
Post by: TonyT on May 13, 2007, 11:44:15 PM
Sorry, Don't quite understand what you
mean by 'you may be getting a copy'.


That, Tony, is a really well written piece.
sinc mentioned overloading and I started looking at it but you've made it easy to figure out.
I have been trying the object way and so far haven't been successful.
Besides being a bad way to do it, it also seems a bit dodgy in that you may be getting a copy. Boxing is interesting but not easy to actually use.
The overloading is the GO.
Title: Re: Fuzz and doubles.
Post by: Bryco on May 14, 2007, 12:22:27 AM
Nor do I. Too much reading in one weekend.
Title: Re: Fuzz and doubles.
Post by: Kerry on May 14, 2007, 06:29:10 PM
...............
Well, I think one thing you still haven't figured out, is the fact
that there's significant differences beween VB6/VBA and C#
and VB.NET.  The advice I generally give to someone coming
from VB6/VBA is to try to forget much of what they know
about those languages, and start over.

...................

Excellent and helpful post.