Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: [Win32, C, and way OT] C floats, doubles, and their equivalence

by ig (Vicar)
on Jul 18, 2009 at 15:53 UTC ( [id://781350]=note: print w/replies, xml ) Need Help??


in reply to [Win32, C, and way OT] C floats, doubles, and their equivalence

Not a solution, but What Every Computer Scientist Should Know About Floating Point Arithmetic may help you understand what is happening and how to code to avoid the problems.

update: there are many surprising/disappointing features in floating point hardware and software. If you dump the internal representations of the values in your program, you might discern what is happening. I would consider whether values are rounded or truncated when converted from double to float, for example. It appears to be handled differently in the different contexts in your program. If you know what the conversion is doing, you should be able to test and make appropriate adjustments so that the result of the conversion is what you want. Alternatively, you might use a well defined/implemented function to perform the conversion rather than relying on the compiler built-in function.

  • Comment on Re: [Win32, C, and way OT] C floats, doubles, and their equivalence

Replies are listed 'Best First'.
Re^2: [Win32, C, and way OT] C floats, doubles, and their equivalence
by syphilis (Archbishop) on Jul 18, 2009 at 16:26 UTC
    I don't think it helps ... unless I've missed something in there.
    Basically, if I have:
    float x = 123.1; float y = 123.1;
    then I expect x == y to be true - and every compiler that I have at my disposal supports that expectation.
    Similarly, if I have:
    float x = 123.1; double y = 123.1;
    then I expect x == (float)y to be true - and every compiler that I have at my disposal (except MSVC++ 7.0) supports that expectation.
    What I'm seeking is some means of bringing the insane MSVC++ 7.0 (and presumably all other MSVC++ versions prior to 8.0) behaviour into line with the behaviour of these other sane compilers.

    It's a question of consistency between compilers. Unless I'm relying on behaviour that the standards classify as "implementation dependent" or "undefined", then it should be the same with all compilers. (If I *am* relying on "implementation dependent"/"undefined" behaviour, then PDL needs a siginificant rewrite - because there are a number of places where the PDL sources assume that behaviour is neither "implementation dependent" nor "undefined".)

    Cheers,
    Rob

      The IEEE standards specify the binary formats, but not the functions (hardware or software) that manipulate them.

      The C standards leave some relevant details undefined or implementation dependent. I don't recall that the exact format of floating point numbers is specified or that the details of conversions are specified (e.g. rounding Vs. truncating).

      There are many relevant hardware and software features that sane people might be inclined to call bugs.

      The operations you are performing in your test program are conceptually simple, yet your experience demonstrates the variability that exists in implementations. For floating point calculations generally, not only does changing the compiler make a difference, but sometimes running the same executable on different hardware makes a difference.

      I would be surprised if Microsoft would fix the old compiler, even if you sent a bug report - their response would almost certainly be that they have fixed it in release 8.0. Even if they did provide a patch for the older compiler, it might be difficult to get everyone compiling your program to install the patch before compiling. You could test for the bug in your test suite and fail the build if it is present.

      If you haven't already, you might try different combinations of of compiler options. Sometimes changing optimization or debug settings will make a difference to such issues.

      If PDL is doing non-trival floating point calculations and must work with a variety of combinations of compiler, libraries and hardware, then it will have to cope with varying results. The paper I linked to gives some good guidance for writing floating point calculations and in particular comparisons to minimize and accommodate the variations.

      Similarly, if I have: float x = 123.1; double y = 123.1; then I expect x == (float)y to be true

      I don't know that that is a reasonable expectation. Conversion from double to float is not the exact same operation as the initial assignment. The first is converting the numeric string to a floating point representation. The resulting floating point representation will be very very close to but not necessarily exactly "123.1" or whatever other value you assign to it. By contrast converting double to float is reducing the number of significant digits in a representation that is already approximate. Mismatches between assignment and rounding are always possible.

      In general, exact equalities on doubles and floats is not a good idea. I'm a little surprised that PDL code is assuming that it is. I was always taught instead to do x - y < EPSILON where EPSILON is some value small enough to make the difference between the two numbers irrelevant for the purposes of your computation. If exact decimal precision is needed (as is sometimes the case in financial calculations) then one needs to use one of the many C/C++ arbitrary precision libraries.

      Best, beth

      Update: x - y < EPSILON assumes it is known that x >= y (i.e. prior code has tested that assertion). In the general case where that assertion has not been verified, see comment by roboticus below.

        I don't know that that is a reasonable expectation

        Yes, I don't know if it's reasonable, either - but it does appear to be reliable except when a pre-VC8 MS Compiler is being used.

        In general, exact equalities on doubles and floats is not a good idea. I'm a little surprised that PDL code is assuming that it is

        No - that assumption is not being made ... well, not explicitly, anyway. The exact problem I'm looking at is not all that complex:

        Basically, if you have a piddle (array) of values, you should be able to call setvaltobad(123), and every occurrence of 123 in that piddle will be changed to 'BAD'. So, if we have a piddle of floats [1/3, 2/3, 1, 4/3] and we call setvaltobad(2/3), then that piddle should become [1/3, BAD, 1, 4/3]. And that's exactly what happens ... unless we're using one of those older Microsoft Comnpilers (in which case the piddle remains unchanged).
        Now, part of the problem is probably that setvaltobad(2/3) passes a double (NV). But that's not a problem with any compiler other than the ones I've already specified (afaik).

        It's the sort of thing that probably won't ever affect anyone ... but there's a test for this in the current test suite, that test fails when PDL is built with one of the older Microsoft Compilers, and it would be nice to fix that failure without having to go to too much trouble.

        (Unfortunately, it has already become "too much trouble" :-)

        Cheers,
        Rob
        ELISHEVA:

        Minor correction: fabs(x - y) < EPSILON to catch the case where y is greater than x.

        ...roboticus

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://781350]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (7)
As of 2024-04-23 08:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found