Win32 MAth Error Double to Int Conversion

I have a rather large win32 program I'm building and have come across a rather annoying anomoly. For some reason at certain values like 46.00000, when I try to change it to an integer it becomes 45. I can take similar code into a console program and everything is fine, but it won't work in my windows program.

More specifics:

[code]
double tScoref = 46.000000;
int tScore;
char tempTest[15];

sprintf(tempTest, "%f", tScoref);
// print function - either cout or SetDlgItemText()


tScore = (int)tScoref;
/* or */
tScore = tScoref;

sprintf(tempTest, "%d", tScore);
// print function - either cout or SetDlgItemText()



[/code]

tScore holds 46, as expected in my console program, but it holds 45 in my windows version. Of course my windows version is much more elaborate with SetDlgItemText(), etc., but I have used the same sprintf() functions to return the values of tScore and tScoref in the same ways.

I'm using WindowsXP and Dev-C++ 4.9.9.2 and any thoughts are gratefully appreciated. I'm trying to use a single value (double) to hold two numbers by using the whole part and the decimal part separately. If I can't fix whatever is going on, I will have to abandon that method.

Thanks for any assistance.

Take Care,
Ed

Comments

  • : I have a rather large win32 program I'm building and have come
    : across a rather annoying anomoly. For some reason at certain values
    : like 46.00000, when I try to change it to an integer it becomes 45.
    : I can take similar code into a console program and everything is
    : fine, but it won't work in my windows program.
    :
    : More specifics:
    :
    : [code]:
    : double tScoref = 46.000000;
    : int tScore;
    : char tempTest[15];
    :
    : sprintf(tempTest, "%f", tScoref);
    : // print function - either cout or SetDlgItemText()
    :
    :
    : tScore = (int)tScoref;
    : /* or */
    : tScore = tScoref;
    :
    : sprintf(tempTest, "%d", tScore);
    : // print function - either cout or SetDlgItemText()
    :
    :
    :
    : [/code]:
    :
    : tScore holds 46, as expected in my console program, but it holds 45
    : in my windows version. Of course my windows version is much more
    : elaborate with SetDlgItemText(), etc., but I have used the same
    : sprintf() functions to return the values of tScore and tScoref in
    : the same ways.
    :
    : I'm using WindowsXP and Dev-C++ 4.9.9.2 and any thoughts are
    : gratefully appreciated. I'm trying to use a single value (double)
    : to hold two numbers by using the whole part and the decimal part
    : separately. If I can't fix whatever is going on, I will have to
    : abandon that method.
    :
    : Thanks for any assistance.
    :
    : Take Care,
    : Ed
    :
    [color=Blue]Most likely a DEV C++ issue. 46.0000 is converted to 45.999999999999999... or something like that and then (int) cast will truncate it. Try a few tests, like this one:
    [/color]
    [code]
    double a=46.000000; // btw, try to keep just one zero (46.0)
    double b=a*1000000.0;
    unsigned int n=(unsigned int)b;
    printf ("%d",n); // this may also be the issue in printf() itself.
    [/code]
    [color=Blue]
    I have an idea for a small test:
    [/color]
    [code]
    double a=46.000000;
    int bytes=sizeof (a);
    void* p=&a;

    // Now run a debugger on this and post here what memory dump you see at
    // this 'p' pointer and also, what is 'bytes' in this case.
    [/code]
    [color=Blue]
    I will run the same test in FASM and we compare the results.
    [/color]
  • Thanks for the help, but I must confess to not knowing how to debug windows source. I'm also not able to figure out how to do a memory dump with the Dev-C++ debugger. I consulted the help file, which didn't help. The only thing I could do is watch the variables, etc. Here is what I show:

    [code]
    a = 46
    bytes = 8
    p = (void *) 0x22ff70
    $eax = 0x22ff70
    [/code]

    Anyway, I have no troubles in a console program and can't duplicate the problem in a smaller windows application. I did, however, create a messagebox and fill it with all the important values I could think of. And, it shows that you were right about the value being truncated, but something more disturbing showed up.

    I used sprintf() to convert the values to strings. In the first set I used %d for all the int values and %f for all the double values, but in the rest I used %f for all the values and something showed up. Of course, I suspect this is a sprintf anomoly, but I also think my int values are not truly correct.

    Apparently, my int values are carrying decimal information with them, but the really questionable oddity is highlighted below. How can the integer values be so different for the item in red? Is this because of the %f specifier or is there really something wrong with my int value?

    [code]
    Original tScoref1: 196.010000
    Original tScoref2: 299.010000
    Original tScoref3: 200.016000
    Original tScoref4: 200.010000
    Total tScoref: 895.046000
    tScore = (int)tScoref: 895
    itoa(tScore, tempScore, 10): 895
    tScoref *= 1000: 895046.000000
    [red]tScore *= 1000: 895000[/red]
    tScoref -= tScore: 46.000000
    tScore = (int)tScoref: 45
    [/code]

    [code]
    Original tScoref1: 196.010000
    Original tScoref2: 299.010000
    Original tScoref3: 200.016000
    Original tScoref4: 200.010000
    Total tScoref: 895.046000
    tScore = (int)tScoref: 895.045898
    itoa(tScore, tempScore, 10): 895.045898
    tScoref *= 1000: 895046.000000
    [red]tScore *= 1000: 895045.500104[/red]
    tScoref -= tScore: 46.000000
    tScore = (int)tScoref: 45.999969
    [/code]

    The first four tScorefs shown above are read in from a binary file as doubles into a struct with about 25 elements. I've also tried replacing the summing of the four values by making tScoref equal to 895.046000 directly and the following is the result:

    [code]
    Total tScoref: 895.046000
    tScore = (int)tScoref: 895.045898
    itoa(tScore, tempScore, 10): 895.045898
    tScoref *= 1000: 895046.000000
    [red]tScore *= 1000: 895046.000104[/red]
    tScoref -= tScore: 46.000000
    tScore = (int)tScoref: 46.000000
    [/code]

    I left the highlight because that integer value still shows the extra value, which I can't understand. The only change in the above routine between outputs is the replacement of the %d specifier with %f. tScore is still an integer, defined as such at the beginning of the section.

    Now, in case this isn't annoying enough, if I change the values of two of the original tScorefs in the binary source file, it acts like the direct setting of the tScoref variable:

    [code]
    Original tScoref1: 196.010000
    [blue]Original tScoref2: 299.016000
    Original tScoref3: 200.010000[/blue]
    Original tScoref4: 200.010000
    Total tScoref: 895.046000
    tScore = (int)tScoref: 895.045898
    itoa(tScore, tempScore, 10): 895.045898
    tScoref *= 1000: 895046.000000
    [red]tScore *= 1000: 895046.000104[/red]
    tScoref -= tScore: 46.000000
    tScore = (int)tScoref: 46.000000
    [/code]

    This is kind of a show-stopper for me at this point. I have no deadline and no boss wanting this completed, fortunately. I might end up having to do some major changes. But, it's not pressing, so I might just let it set for a bit. I do still need to know what is going on, though... and whether I'm going to have a to do a major rewrite.:-(

    Almost forgot:

    The result of your first test was 46000000

    Thanks for all the help.

    Take Care,
    Ed
  • I've managed to cobble together a very basic windows program that shows the trouble. Run the program and left click in the window to bring up the messagebox. Here's what my messagebox shows:
    [code]
    Original tScoref1: 197.010000
    Original tScoref2: 298.010000
    Original tScoref3: 200.016000
    Original tScoref4: 200.010000
    Total tScoref: 895.046000
    tScore = (int)tScoref: 895.045898
    tScoref *= 1000: 895046.000000
    tScore *= 1000: 895045.500104
    tScoref -= tScore: 46.000000
    tScore = (int)tScoref: 45.999969
    [/code]
    All my code is under "case WM_LBUTTONDOWN:" in the WindowProcedure. You can change values and specifiers to see what's going on with my larger program.

    Here's the windows source. I'm compiling under WindowsXP using Dev-C++ 4.9.9.2.

    [code]
    #include
    #include
    #include

    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

    char szClassName[ ] = "WindowsApp";

    int WINAPI WinMain (HINSTANCE hThisInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpszArgument,
    int nFunsterStil)

    {
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;

    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);

    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wincl))
    return 0;

    hwnd = CreateWindowEx (
    0,
    szClassName,
    "Double to Int Conversion Problem",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    320,
    240,
    HWND_DESKTOP,
    NULL,
    hThisInstance,
    NULL
    );

    ShowWindow (hwnd, nFunsterStil);

    while (GetMessage (&messages, NULL, 0, 0))
    {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
    }

    return messages.wParam;
    }

    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    switch (message)
    {
    case WM_LBUTTONDOWN:{
    char tempTest[20][20], fullText[400];
    int tScore;

    double tScoref1= 197.010;
    sprintf(tempTest[0], "%f", tScoref1);
    double tScoref2= 298.010;
    sprintf(tempTest[1], "%f", tScoref2);
    double tScoref3= 200.016;
    sprintf(tempTest[2], "%f", tScoref3);
    double tScoref4= 200.010;
    sprintf(tempTest[3], "%f", tScoref4);

    double tScoref = tScoref1+tScoref2+tScoref3+tScoref4;

    sprintf(tempTest[4], "%f", tScoref);

    tScore = (int)tScoref;
    sprintf(tempTest[5], "%f", tScore);

    tScoref *= 1000;
    sprintf(tempTest[6], "%f", tScoref);

    tScore *= 1000;
    sprintf(tempTest[7], "%f", tScore);

    tScoref -= tScore;
    sprintf(tempTest[8], "%f", tScoref);

    tScore = (int)tScoref;
    sprintf(tempTest[9], "%f", tScore);

    strcpy(fullText, "Original tScoref1: ");
    strcat(fullText, tempTest[0]);
    strcat(fullText, "
    Original tScoref2: ");
    strcat(fullText, tempTest[1]);
    strcat(fullText, "
    Original tScoref3: ");
    strcat(fullText, tempTest[2]);
    strcat(fullText, "
    Original tScoref4: ");
    strcat(fullText, tempTest[3]);
    strcat(fullText, "
    Total tScoref: ");
    strcat(fullText, tempTest[4]);
    strcat(fullText, "
    tScore = (int)tScoref: ");
    strcat(fullText, tempTest[5]);
    strcat(fullText, "
    tScoref *= 1000: ");
    strcat(fullText, tempTest[6]);
    strcat(fullText, "
    tScore *= 1000: ");
    strcat(fullText, tempTest[7]);
    strcat(fullText, "
    tScoref -= tScore: ");
    strcat(fullText, tempTest[8]);
    strcat(fullText, "
    tScore = (int)tScoref: ");
    strcat(fullText, tempTest[9]);

    MessageBox(hwnd, fullText, "Compilation of values", MB_OK);


    }
    break;
    case WM_DESTROY:
    PostQuitMessage (0);
    break;
    default:
    return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
    }
    [/code]

    Thanks again for any help.

    Take Care,
    Ed
  • : I've managed to cobble together a very basic windows program that
    : shows the trouble. Run the program and left click in the window to
    : bring up the messagebox. Here's what my messagebox shows:
    : [code]:
    : Original tScoref1: 197.010000
    : Original tScoref2: 298.010000
    : Original tScoref3: 200.016000
    : Original tScoref4: 200.010000
    : Total tScoref: 895.046000
    : tScore = (int)tScoref: 895.045898[color=Blue]
    : tScoref *= 1000: 895046.000000
    : tScore *= 1000: 895045.500104
    : tScoref -= tScore: 46.000000[/color]
    : tScore = (int)tScoref: 45.999969
    : [/code]:

    I was going to post something, but it seems the banned word list has been tightened a fair bit, and now it's strangling my story. I'll see if I can get the webmasters advice on it, and if I can I'll post my original message with actually not-so-very-useful comments :P
    Best Regards,
    Richard

    The way I see it... Well, it's all pretty blurry
  • [color=Blue]
    I'll try your code in VS 2005. I see the double is 8 bytes in DEV C++. In FASM the memory dump at 'p' will be this one:
    [/color]
    [code]
    ;
    ; Value 46.0 as 8 bytes double
    ;
    00 00 00 00 00 00 47 40
    [/code]
    [color=Blue]
    Try to dump it like this:
    [/color]
    [code]
    double a = 46.0;
    unsigned char* p = (unsigned char*) &a;
    char s [32];
    char* pdump = s;

    for (int i=0; i<8; i++)
    {
    wsprintfA (pdump, "%02X ", p[i]);
    pdump += 3;
    }

    // At this point look on buffer 's' in debugger
    [/code]
  • Thanks again. I still can't find any buffers or way to do a memory dump in the console debugger and I can't get the thing to work for a win32 yet - just ignorance on my part.

    Instead, I wrote the following to check the memory location and it returned the same as your machine (00 00 00 00 00 00 47 40):

    [code]
    union dataTest
    {
    double a;
    char c[8];
    } test;

    test.a = 895.046;

    for (int i=0;i<8;i++)
    printf("%02X ", abs(test.c[i]));

    printf("


    ");
    [/code]

    Could you try the above routine with test.a = to 895.046 and see what you get? I get the following:

    12 7C 3F 35 5E 08 75 40

    Thanks again for the help. I'm not sure where I'm going to head with this, but it is interesting to pursue for awhile at least. At some point I will have to decide on a direction, I suppose...

    Take Care,
    Ed
  • : Thanks again. I still can't find any buffers or way to do a memory
    : dump in the console debugger and I can't get the thing to work for a
    : win32 yet - just ignorance on my part.
    :
    : Instead, I wrote the following to check the memory location and it
    : returned the same as your machine (00 00 00 00 00 00 47 40):
    :
    : [code]:
    : union dataTest
    : {
    : double a;
    : char c[8];
    : } test;
    :
    : test.a = 895.046;
    :
    : for (int i=0;i<8;i++)
    : printf("%02X ", abs(test.c[i]));
    :
    : printf("


    ");
    : [/code]:
    :
    : Could you try the above routine with test.a = to 895.046 and see
    : what you get? I get the following:
    :
    : 12 7C 3F 35 5E 08 75 40
    :
    : Thanks again for the help. I'm not sure where I'm going to head
    : with this, but it is interesting to pursue for awhile at least. At
    : some point I will have to decide on a direction, I suppose...
    :
    : Take Care,
    : Ed
    :
    [color=Blue]I get (VC++ compiler from VS 2005) the following dump for 895.046:
    EE 7C 3F 35 5E F8 8B 40

    Try Visual Studio Express if you need only Win32 API - it is great!
    [/color]
  • : [color=Blue]I get (VC++ compiler from VS 2005) the following dump
    : for 895.046:
    : EE 7C 3F 35 5E F8 8B 40
    :
    : Try Visual Studio Express if you need only Win32 API - it is great!
    : [/color]
    Interesting - I wonder why the difference.

    I looked at Visual Studio Express a little while ago. I was really interested until I saw all the web tracking in the licensing. I know it's monetarily free, but there are other costs and I'm not really interested in MS tracking my programming at any level. I know there is probably tracking of other stuff going on that I don't know about and MS is at least up front about that part, but still...

    Anyway, I also have a commercial (old) Borland compiler (full ide) that usually works well, too. But sometimes I run into trouble transferring a full project between the two. I get tied up in the .rc and .def files area and sometimes the older Borland doesn't recognize something and I have to search. The Borland package has excellent documentation, though. It also includes a lot of non-standard, but useful things.

    But, here's something [b][italic]really[/b] interesting. I compiled the small windows test in my Borland package and got the following info back:

    [code]
    Original tScoref1: 197.010000
    Original tScoref2: 298.010000
    Original tScoref3: 200.016000
    Original tScoref4: 200.010000
    Total tScoref: 895.046000
    [red]tScore = (int)tScoref: 0.000000[/red]
    tScoref *= 1000: 895046.000000
    [red]tScore *= 1000: 0.000000[/red]
    tScoref -= tScore: 46.000000
    [red]tScore = (int)tScoref: 0.000000[/red]
    [/code]

    What's up with that?:-o

    I think I'm going to set this aside for a few days and probably just approach it differently later.

    Thanks for all the help.

    Take Care,
    Ed
  • : But, here's something [b][italic]really[/b] interesting. I compiled
    : the small windows test in my Borland package and got the following
    : info back:
    :
    : [code]:
    : Original tScoref1: 197.010000
    : Original tScoref2: 298.010000
    : Original tScoref3: 200.016000
    : Original tScoref4: 200.010000
    : Total tScoref: 895.046000
    : [red]tScore = (int)tScoref: 0.000000[/red]
    : tScoref *= 1000: 895046.000000
    : [red]tScore *= 1000: 0.000000[/red]
    : tScoref -= tScore: 46.000000
    : [red]tScore = (int)tScoref: 0.000000[/red]
    : [/code]:
    :
    : What's up with that?:-o
    :
    : I think I'm going to set this aside for a few days and probably just
    : approach it differently later.
    :
    : Thanks for all the help.
    :
    : Take Care,
    : Ed
    :
    [color=Blue]Very strange results... it would have been interesting to disassemble these lines and see what is going on in Borland.

    Maybe, you can send me the EXE file built by the Borland package? Just rename it or zip it (maybe both), so my HOTMAIL will not clean it out. Also, in that case WM_LBUTTONDOWN: put "DebugBreak();" so it will attach debugger when this line will get hit. Also, make sure it is linked statically - I do not have any Borland environment.[/color]
  • I've sent you the exe (txt) and cpp files.

    [red]Please note that the exe file crashes on my system and wants to send the report to MS when I include the DebugBreak(); line.[/red]

    This may be because my Borland debugger is 16 bit. But, it also crashes under my Dev-C++ IDE. I suppose it might still be invoking the Borland debugger?

    As to my intial program, I rewrote all my doubles to integers and actually removed about 75% of the lines I had used for handling them as doubles. It wasn't quite as bad a rewrite as I thought it would be - only a couple hundred lines, at most.

    Thanks again for all the help.

    Take Care,
    Ed
  • I haven't read this thread too carefully, but you should be aware of how float numbers work. They never ever contain a fixed value. So you can never expect them to have a certain value, and you can never check them with the equality operators == and !=.

    Here is a good link: http://c-faq.com/fp/
  • : I haven't read this thread too carefully, but you should be aware of
    : how float numbers work. They never ever contain a fixed value. So
    : you can never expect them to have a certain value, and you can never
    : check them with the equality operators == and !=.
    :
    : Here is a good link: http://c-faq.com/fp/
    [color=Blue]The constants loaded from FPU itself are OK to check for equality, because FPU hardware always loads the same constant (like PI). However, AFTER any FPU operations the precision is lost (in most cases) and equality no longer works.[/color]
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories