Hello
i have spent hours and days and couldn't find how i can make a variable that has rounded to 2 decimal digits. But i dont want to use myVariable.value....or myVariable()....styles. In the net i have seen something like BCD that is related for official accounting issues but i coudn't make any use of it because i didn't understand it. I am neither a prorammer(i would love to be one) nor a student( meaning something related with assignment or schools) but i make some extensions to the accounting software that i use. Thanks to every one especially Danny

Recommended Answers

All 36 Replies

You can't do it with the floats or doubles in C/C++ language because of the way they are stored in memory. If you use C/C++ languages and want great internal precision then you will need to use some other math package that will allow it. myVariable.value may be unavoidable.

Maybe I'm missing something here, but one of the hardest things for me is to remember the computer doesn't do things like I do. I always try to get the computer to do things the way I do when I should be taking advantage of the special characteristics of the computer (or the software) to get the job done. The reason I bring this up is that I see no problem letting the computer/software use floats or doubles internally with whatever precision it wants, and then when it comes time to display the "final" numbers so us humans can read it, use the capabilities of the software to round off to 2 decimals for display purposes (things like setprecision() or ceiling()/floor()/whatever).

Hello
i have spent hours and days and couldn't find how i can make a variable that has rounded to 2 decimal digits. But i dont want to use myVariable.value....or myVariable()....styles. In the net i have seen something like BCD that is related for official accounting issues but i coudn't make any use of it because i didn't understand it. I am neither a prorammer(i would love to be one) nor a student( meaning something related with assignment or schools) but i make some extensions to the accounting software that i use. Thanks to every one especially Danny

Extending software means conforming to the rules of that software. Most likely your application exposes some types and functions for interfacing with it, and that's where you find out how to store monetary values. It would help if you can tell us what the accounting software is that you're extending.

I want to have a variable that is born as rounded to 2 decimal digits,processed as rounded to 2 decimal digits and finally posted to MS SQL as rounded to 2 decimal digits. Where i see the data i want to see it as #.##0,00 The way I want to do this with vc++ is like this:

//
//something to create myDouble
//
...
int var0;
double var1;
myDouble var2; // it is a rounded off to 2 decimal digits double 
....

you can't consistently do that with doubles or floats. I have never used MATHLIB so I don't know if it will do what you want or not, but you can research it.

Would it suffice to declare MyDouble as a wrapper class to type double?

It could have:
1) a single variable of type double called data.
2) default constructor setting value to 0.00
3) constructor taking type double and assigning it to data
4) overloaded conversion operator to convert type double to type MyDouble implicitly
5) overloaded << operator that uses setprecision(2) to limit output to 2 decimal points
6) overloaded >> to input double into data
7) overloaded math operators as needed

Would it suffice to declare MyDouble as a wrapper class to type double?

Probably not because such a class still has all the properties of double data type. You would need a class that does not depend on either float or double if you always want an exact precision. doubles and floats can not give that to you.

Probably not because such a class still has all the properties of double data type. You would need a class that does not depend on either float or double if you always want an exact precision. doubles and floats can not give that to you.

I guess his last two points would take care of that one....

5) overloaded << operator that uses setprecision(2) to limit output to 2 decimal points
6) overloaded >> to input double into data

I guess his last two points would take care of that one....

only on output -- internal representation of the double will not change. No matter how you slice it a double is still a double regardless of setprecision. The only way to get around the internal representation problem is to not use doubles at all.

only on output -- internal representation of the double will not change.

Isn't that what he wants.. ?

I want to have a variable that is born as rounded to 2 decimal digits,processed as rounded to 2 decimal digits and finally posted to MS SQL as rounded to 2 decimal digits.

Isn't that what he wants.. ?

No, I don't think so.

At some point for MyDouble to be a useful class it will need to be manipulateable. For example I can imagine that a variable of type MyDouble should be able to be divided by another variable of type MyDouble. If MyDouble were always restricted to a rigid internal representation with just two decimal places, then you would have to have any values beyond the second decimal place ignored, like all decimal places are with integer division. That wold seem even more odius than the "inexact" nature of doubles beyond the 10th, or whatever, decimal point when MyDouble were declared as a wrapper class to type double.

However, if one were to insist on such a rigid internal representation, one could consider the possibility of the MyDouble type having it's primary data variable being a string which is restricted to two characters to the right of the decimal point. Then the internal string could be converted to type double, or two type ints (one to represent the whole number value and one to represent the decimal value * 100) (or a single type long???), to do the math and then be converted back to a string once the math is done, (of course it may still need to be rounded to the second decimal point if division is involved [at least I don't think anything other than division will affect the 2 decimal point internal precision]).

Are not all user defined types in C/C++ just a conglomeration of predefined types put together in different combinations if you dig deep enough? If so, since there is no predefined data type that is restricted to two decimal place accuracy in C++ then there will never be a user defined type that can accomplish the task, in the most rigid sense, either. Which means at some point, if you are going to restrict yourself to using C/C++ to accomplish the task, then there must be a compromise of one sort or another along the way. Meaning we're back to Ancient Dragon's first repsonse.

5) overloaded << operator that uses setprecision(2) to limit output to 2 decimal points

setprecision doesn't control the number of decimal points that can be outputted but the total number of digits worth of precision you want.

eg.

double val = 1.23456 ;
cout << setprecision( 1 ) << val ; // will output is 1 and not 1.2

double var = 1.8234 ;
cout << setprecision( 1 ) << var ; // will output 2 and not 1

I want to have a variable that is born as rounded to 2 decimal digits,processed as rounded to 2 decimal digits and finally posted to MS SQL as rounded to 2 decimal digits.

You can always do something weird as this:

// WARNING: Untested
#include <iostream>
#include <cstring>
#include <sstream>

class MyDouble
{
    public:
        MyDouble( ): var_(0.0) { } ;

        MyDouble( double var )
        {
            var = var * PRECISION ;
            var = static_cast<int> ( var ) / PRECISION ;
            var_ = var ;
        }

        friend std::ostream& operator << (std::ostream& ostr, MyDouble& obj )
        {
            ostr << obj.var_ ;
            return ostr ;
        }

    private:

        static const double PRECISION = 100 ;
        double var_ ;
} ;

int main( )
{
    using namespace std;

    MyDouble a( -9.5 ) ;
    cout << a ;

    cin.get( ) ;
    return EXIT_SUCCESS ;
}

Isn't that what he wants.. ?

No the output is not enough for me. I am very confused. I thought that this issue was a simple, widespread one and the answer would be an easy one. Some huge number of people should have needed it before me. Ok I understand that it is not the way I thought it was. The second thing, I perceived and believed that C and its derivatives were strong tools for programming. Now comes my new questions: Can you tell me? Where are the answers and/or the people who know the answers are hidden? In my first post I had said that i had searched hard in the net. Where can i go back to the beginning to learn searching in the net?(Seriously and truly) Is the time of C and the derivatives over. Thanks to every one for their interests and offers.

No the output is not enough for me. I am very confused. I thought that this issue was a simple, widespread one and the answer would be an easy one. Some huge number of people should have needed it before me. Ok I understand that it is not the way I thought it was. The second thing, I perceived and believed that C and its derivatives were strong tools for programming. Now comes my new questions: Can you tell me? Where are the answers and/or the people who know the answers are hidden? In my first post I had said that i had searched hard in the net. Where can i go back to the beginning to learn searching in the net?(Seriously and truly) Is the time of C and the derivatives over. Thanks to every one for their interests and offers.

I already posted a dummy implementation on how you should go about creating your own datatype from the existing ones. If that is not acceptable to you then the only option left is to use the technique used by Compiler writers and Language designers to create your own primitive datatype -- a task which would definately not be easy on all accounts.

But I don't think that would allow for trailing zeros as needed beyond the decimal point so that there are precisely 2 decimal points every time (for example that 100 is 100.00 or 10.7 is 10.70, etc ). And it doesn't round off to 2 decimals, it truncates at 2 decimals.

>>Some huge number of people should have needed it before me.

True, but not all of them were as rigid in their requirements as you have requested. Accepting the "foibles" of the double datatype is a common compromise as is using another language that has the appropriate data type you want inherent to the language. Other possible compromises have been discussed within the thread as well. However, no language can do everything everybody wants as easy as they want. If there were such a language there would only be one language. Short of that there is usually a compromise someplace along the way.

I have been testing ~S.O.S~'s example and it seems to work pretty well with the values I tested. Just a small change to the program (VC++ 6.0 doesn't like const initialized inside the class). But it works (rounds to 2 decimal places) with both positive and negative values. Don't know if it will work with ALL possible values though.

// WARNING: Untested
#include <iostream>
#include <cstring>
#include <sstream>
#include <cmath>

static const double PRECISION = 100 ;

 
class MyDouble
{
    public:
        MyDouble( ): var_(0.0) { } ;
 
        MyDouble( double var )
        {
            double int_part;
            var = var * PRECISION ;
            double fract_part = modf(var, &int_part);
            if(fract_part < 0)
            {
                if( fract_part < -0.5F)
                var--;
            }
            else
            {
                if( fract_part > 0.5F)
                    var++;

            }
            var = static_cast<int> ( var ) / PRECISION ;
            var_ = var ;
        }
 
        friend std::ostream& operator << (std::ostream& ostr, MyDouble& obj )
        {
            ostr << obj.var_ ;
            return ostr ;
        }
 
    private:
 
        double var_ ;
} ;
 
int main( )
{
    using namespace std;
 
    MyDouble a( 7.311 ) ;
    cout << a ;
 
    cin.get( ) ;
    return EXIT_SUCCESS ;
}

I still don't see how that example will gaurantee 2 decimal places if there is less than that in the original input. I do see how it restrict to 2 decimal places if there is more than that and how it rounds up.

Here's my initial, untested version of how to gaurantee rounding to 2 decimal places and guaranteeing 2 decimal places, again, untested in real world setting.

struct Currency
{
    string data;
    string input;
    Currency(string i) 
    {
       input = i;
    }
    Currentcy(double d)
    {
       stringstream ss >> d;
       input = ss.str();
    }
    
    void gaurantee2decimalPlaces()
    {
        //find decimal point
        for(i = 0; i < input.length(); ++i)
            if(input[i] == '.')
              break;

        if(input[i] == '\0')  //no decimal found
          data = input + ".00";
        else if(input[i + 2] == '\0')  //1 decimal place only
          data = input + "0";
        else if(input[i + 3] != '\0')  //more than 2 decimal places
        { 
           if(input[i + 3] > '4')  //need to round up
           {
             //convert string to double
             double d = stod(input.c_str()); 
             
             //round up
             d += .005;

             //convert double back to string
             stringstream ss;
             ss >> d;
             data = ss.str();
            }
             //resize string to just 2 decimal places
             data[i + 2] = '\0';
         }
     }
     
     friend ostream & operator <<(ostream & os, const Currency c)
     {
         os << c.data;
         return os;
     }
}

>>I still don't see how that example will gaurantee 2 decimal places if there is less than that in the original input
doubles always have a lot of decimal places regardless of how they are rounded. If you using printf() you will see that

double a = 1.23F;
printf("%.6f\n",a);

Output of above will be 1.230000 (6 decimal places). You should not be concerned about just 1 decimal place because internally the double will always have quite a few (actual number will vary with the integer part of the number). If the number is large enough you might get something like this: 1528.535047 × 102 -- which is scientific notation.

Here is a pretty good explaination

Use this to output 2 decimals even if rounded to one cout << setfill('0') << left << setw(4) << a ;

I still don't see how that example will guarantee 2 decimal places if there is less than that in the original input. I do see how it restrict to 2 decimal places if there is more than that and how it rounds up.

Obviously I can't post entire solutions being a moderator -- its against the site policy... ;)

The OP can always change the << function to implement the behaviour of printing to exactly two decimal points. And since the OP will be using the printing operation infrequently ( the values are meant to basically put in and pulled out from a database I believe ), the overhead of the < < function wouldn't be too much....

But seriously for such requirements whatever we suggest him would be too slow. Consider what you posted -- to many string operations just for the sake of initializing the MyDouble object. Not to forget that strings are classes in C++ and call constructors and destructors. Also since you have stored the data in strings instead of actual double, your realization is too much an overkill considering you have to write your own procedures for multiplication, division, addition, subtraction -- all of them involving string objects, along with taking each and every possible condition into consideration.

Thats why I said to OP:

If that is not acceptable to you then the only option left is to use the technique used by Compiler writers and Language designers to create your own primitive datatype -- a task which would definately not be easy on all accounts.

Here is a free math library that allows (nearly) unlimited precision. I know there are others too.

In the net i have seen something like BCD that is related for official accounting issues but i coudn't make any use of it because i didn't understand it.

Do you mean where floating point is completely eschewed because of inherent difficulties, and instead integer math is used? Such that instead of trying to store 123.45 as a floating-point value, you instead store 12345 as an integer?

BCD as I understand it is encoded in a series of bytes, the number of bytes depends on the desired level of precision and maximum desired number of digits. The value of Bill Gates net worth (64 billion the last time I saw it) (64,000,000,000) which would require 6 bytes (11/2) for packed BCD (two digits per byte). I don't know if this is still used in accounting systems or not.

As you can tell from my gaffe regarding setprecision() (controls significant digits, not decimal precision), my experience with use of stream manipulators is limited. My experience with formatted output using C I/O is even more limited. My first question would therefore be: Is there a C++ stream manipulator/flag that will restrict display of decimal places to 2 (or any other desired decimal place value for that matter) for any random variable of type double similar to what the .* flag appears to do in C using printf()? Using the combination of setfill(), left, and setw() seems to require that you know the number of digits in a type double and whether they are on the right or the left of the decimal point.

Given the task of devising a type in C++ that gaurantees two decimal place precision with display of trailing zeros if appropriate (a type to use for Currency manipulations, or at least Currency based on the decimal system as in the USA) to me it looks like manipulation of strings seems the most viable option. I'd prefer to base the Currency type on type double but I can't see how to limit decimal places to 2 in the output, with trailing zeros if need be, using the set of stream manipulators available in the references I have available without being able to figure out the number of digits in the variable and how many are on which side of the decimal point. Given the .* flag in printf() maybe the answer would be to base the Currency type on type double and use the C style formatted output, which is legal, rather than stream manipulators/flags, and not worry about mixing C and C++ I/O in the same program, which I try very hard not to do. Or maybe it just shouldn't be done in C++. Maybe the easiest "solution" to using a "Currency type" in C/C++ would be to use C with currency being type double and the output always foramtted with the .* flag.

Do you mean where floating point is completely eschewed because of inherent difficulties, and instead integer math is used? Such that instead of trying to store 123.45 as a floating-point value, you instead store 12345 as an integer?

No I don't mean using integer math as an alternative to using floating value.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.