Menu

C++ Typecasting

Ultim
2008-07-23
2012-09-26
  • Ultim

    Ultim - 2008-07-23

    What's the difference between these two pieces of code?

    float as = 80.02;
    as *= 100;
    int ad = (int)as;
    cout << ad;
    system("pause>nul");

    /////////////////////////

    float as = 8002;
    int ad = (int)as;
    as = (float)ad;
    cout << ad;
    system("pause>nul");

    Hint: This is not a compiler specific bug

     
    • Keith

      Keith - 2008-07-29

      Clifford:
      Thanks mucho for the links! There's a lot of good reading there, and I have it bookmarked for doing so!

      Ultim:
      Glad there was something there to help. I'm very much the amateur--just interested in the math of dollars and cents.

       
    • Anonymous

      Anonymous - 2008-07-23

      It seem to me a typical question of the exam of a C++ course, so start thinking in both sentences line by line keeping in mid the standard and explicit type-conversion rules.

       
    • cpns

      cpns - 2008-07-23

      Why do you ask? The fact that you gave us a hint implies you know the answer. Are you attempting to challange us or trying to get a free ride on your homework.

      If the first, who cares, I've got real programming challanges to tackle every day on top of other people's I choose to solve here, besides it is not that much of a challange. If the latter, do your own.

      Clifford

       
    • cpns

      cpns - 2008-07-23

      Besides surely that is the wrong question? The differences are obvious - they are just different. The question should be "Why do these pieces of code display different results?"

      Clifford

       
    • Ultim

      Ultim - 2008-07-24

      Haha glad someone actually tested the code out. And very good point in your last post, Clifford; I am definitely asking that question, "Why do these pieces of code display different results?" They are both passing the value, 8002, through type conversion from float to int. Yet the first spits out 8001, the second 8002! I was shocked and upset (and not to mention confused) to find this bug. This little bit of code is a common suggestion across the internet to fixing floats to be like money (i.e., taking off decimal places past two places), but it is very flawed.
      (Sorry about that "as = (float)ad;" line in the second one. It wasn't supposed to be there, but doesn't affect the results.)

       
    • cpns

      cpns - 2008-07-24

      > Haha glad someone actually tested the code out

      Who did? It is predictably flawed.

      So is this a challange or a question? Are you still shocked, upset and confused, or do you know the solution and are merely testing?

      In the first example the value of as is not 8002 before the cast as you suggest but rather whaterevr 80.02f * 100.0f evaluates to, which is unlikely to be 8002 precisely.

      A solution in case 1 is:

      int ad = (int)(as + 0.5f);

      But in real-world financial applications such code would be unsatisfactory. Binary floating point should never be used in financial applications. See: http://www2.hursley.ibm.com/decimal/decifaq1.html C# has a decimal floating-point data type which is intended for such applications, it is really just a built-in alias for the underlying .NET System.Decimal structure, so can be used in any .NET language. In ISO C++ or C you need library support for a decimal data type. I believe such support is being considered for C++0x the next ISO standard for C++.

      Clifford

       
    • Ultim

      Ultim - 2008-07-27

      Good! This is embarassing. What do... say, Unix programmers do for serious decimal computations then? What is generally used for bank calculations and all that, for that matter?

       
      • cpns

        cpns - 2008-07-27

        At this point I would say that you had enough information to discover that yourself. A choice of solutions are possible:

        http://softwarecommunity.intel.com/articles/eng/3687.htm

        GCC 4.2 and later include support decimal floating point as a built-in data type: http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Decimal-Float.html#index-g_t_0040code_007b_005fDecimal128_007d-data-type-2003

        Such types are being drafted for standard C++ too: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html

        Clifford

         
      • Keith

        Keith - 2008-07-27

        I'm not sure what "real" programmers use--on the Win platform or on Linux / Unix, but I had thought about this at length some years ago and came to the conclusion that anything involving dollars and cents could be expressed internally as ints, rounded to whole pennies. Therefore $5.85 would be carried as 585. (Multiplication and division can be done by adding 0.5; I remember this algorithm exists.

        It wouldn't be too hard an exercise to make a class with some methods for doing just this, or finding someone else's to borrow. (More fun to make your own and then know precisely how they work!)

        One of my future projects most probably will be a payroll toolkit for processing after-the-fact payroll (with a possible upgrade to calculating a payroll check using the IRS's FIT withholding formulas). BEFORE doing anything of the kind, I'll have doped out the class and methods for the dollars-and-cents math because that is one of my perennial complaints with, say, Quickbooks.

        (
        I take clients' Quickbooks printouts and enter them into this old, antique, user-unfriendly DOS software that I still use because it is bulletproof, never loses data, and rounds properly. QBooks doesn't round properly.
        )

        First, I've got to get back to a medium level of competence with C++, about another 40-80 hours of refresher. Then I'm going to do a little analysis of a dice game similar to Cosmic Wimpout but played with regular dice.

        Meanwhile, short answer is figure out the math you want--possibly using ints--then make your own classes. Or investigate the links from Clifford and go that way.

        BTW, thanks to Clifford for the answers you give. I've been watching your replies and am impressed by the time you put into the answers here. Kudos to you!

        Keith

         
    • cpns

      cpns - 2008-07-27

      > anything involving dollars and cents could be expressed internally as ints, rounded to whole pennies.

      That is called fixed-point arithmetic. And I have in the past recommended exactly that solution, and use it all teh time in embedded systems (not for money, but other real world values). The problem is that it has limited range; for money with 'cent' approx +/- $21 million, which would not work even for a lot of small to medium sized businesses. Of course a 64bit value would be a better bet. The IBM link I posted in the first instance explains these limitations with examples using the GDP of nations. Given the economic state of say Zimbabwe at the moment where they have just started minting $100 billion, it is less than practical generally.

      I did come across this: http://www.codeproject.com/KB/mcpp/decimalclass.aspx which does exactly what you are suggesting, and you might find useful. I did not post it before, becaus the author starts by saying how his intent is to implement C#'s decimal type for C++, but C# decimal is floating point, and his implementation is not. Moreover you could just use System.Decimal in C++/CLI

      Clifford

       
      • cpns

        cpns - 2008-07-28

        ... also (as also mentioned in the IBM link), when performing say interest calculations, you need more than two decimal places because the interest operand is not a monetry value and may not be precisely represented in two decimal places. In fact it is unlikely in any divide or multiply operation that both operands will be monetary - it makes no real-world sense to do such a thing - its always going to be tax, interest, growth, etc.

        Clifford

         
    • Ultim

      Ultim - 2008-07-28

      Thanks, Keith, about the int of cents. Good workaround.
      I've decided to just keep the money in my program as strings until calculations need to be made. Pros: When necessary, decimals can be easily lopped off and resulting value shipped to float type. Can store pretty much any size number, from both ways before and after the decimal. Cons: MUST convert to float for any calculations. Cannot convert back to string afterwards.

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.