tags:

views:

621

answers:

9

Hi all,

I was wondering whether it is possible to limit the number of characters we enter in a float. I couldn't seem to find any method. I have to read in data from an external interface which sends float data of the form xx.xx. As of now I am using conversion to char and vice-versa, which is a messy work-around. Can someone suggest inputs to improve the solution?

A: 

to print a float use printf(%.2f, float), or similar.

Clangon
I know the semantics for printing such a scenario, but my requirement is of taking in data in a specific format using scanf, cin like functions. I have not come across any such function.
rocknroll
+1  A: 

You can limit the number of significant numbers to output:

http://www.cplusplus.com/reference/iostream/manipulators/setprecision/

but I don't think there is a function to actually lop off a certain number of digits. You could write a function using ftoa() (or stringstream), lop off a certain number of digits, and use atof() (or stringstream) and return that.

Hooked
thanks hooked but I was looking for functions similar to cin, scanf etc. May be some of us can contribute such a function to the C,C++ library as I found this a common requirement among my colleagues working in embedded systems domain.
rocknroll
Those are streams, so I don't know what you mean.
Hooked
The iostream manipulators work with cin, and with fstreams and with stringstreams, and with any other iostream.
Max Lybbert
A: 

You should checks the string rather than the converted float. It will be easier to check the number of digits.

luc
+3  A: 

If you always have/want only 2 decimal places for your numbers, and absolute size is not such a big issue, why not work internally with integers instead, but having their meaning be "100th of the target unit". At the end you just need to convert them back to a float and divide by 100.0 and you're back to what you want.

Andreas F
A: 

Why don't you just round the floats to the desired precision?

double round(double val, int decimalPlaces)
{
    double power_of_10 = pow(10.0, static_cast<double>(decimalPlaces));
    return floor(val * power_of_10 + 0.5) / power_of_10;
}


int main()
{
    double d;
    cin >> d;

    // round d to 3 decimal places...
    d = round(d, 3);

    // do something with d
    d *= 1.75;

    cout << setprecision(3) << d; // now output to 3 decimal places
}
rlbond
What about `double` overflow?
Kirill V. Lyadvinsky
There shouldn't be double overflow unless the exponent is really large, it's just shifting the decimal point.
rlbond
What about precision error? Floats tend not to round very well. See @polyglot's post.
greyfade
Floats round just fine, it's just that they may be off a bit due to only having a finite number of bits that represent the mantissa. That's why you still need `setprecision` for output. However, this would be sufficient to round to the nearest cent for a dollar amount.
rlbond
A: 

There exist no fixed point decimal datatype in C, but you can mimic pascal's decimal with a struct of two ints.

swegi
+3  A: 

This is a slight misunderstanding. You cannot think of a float or double as being a decimal number.

Most any attempt to use it as a fixed decimal number of precision, say, 2, will incur problems as some values will not be precisely equal to xxx.xx but only approximately so.

One solution that many apps use is to ensure that:

1) display of floating point numbers is well controlled using printf/sprintf to a certain number of significant digits,

2) one does not do exact comparison between floating point numbers, i.e. to compare to the 2nd decimal point of precision two numbers a, b : abs(a-b) <= epsilon should generally be used. Outright equality is dangerous as 0.01 might have multiple floating point values, e.g. 0.0101 and 0.0103 might result if you do arithmetic, but be indistinguishable to the user if values are truncated to 2 dp, and they may be logically equivalent to your application which is assuming 2dp precision.

Lastly, I would suggest you use double instead of float. These days there is no real overhead as we aren't doing floating point without a maths coprocessor any more! And a float under 32-bit architectures has 7 decimal points of precision, and a double has 15, and this is enough to be significant in many case.

polyglot
polyglot
std::map<ApproxDoubleClass> is always a pain because std::map assumes that if a==b and b==c then a==c. This of course breaks if ApproxDoubleClass b=a+eps, c = a+2*eps;
MSalters
nasty, nasty, nasty! thanks for the tip, maybe one day I will have the misfortune of seeing something to that effect...
polyglot
+2  A: 

Rounding a float (that is, binary floating-point number) to 2 decimal digits doesn't make much sense because you won't be able to round it exactly in some cases anyway, so you'll still get a small delta which will affect subsequent calculations. If you really need it to be precisely 2 places, then you need to use decimal arithmetic; for example, using IBM's decNumber++ library, which implements ISO C/C++ TR 24773 draft

Pavel Minaev
A: 

If the need is to take 5 digits [ including or excluding the decimal point ], you could simply write like below.

scanf( "%5f", &a );

where a is declared as float.

Fo eg: If you enter 123.45, scanf will consider the first 5 characters i.e., 4 digits and the decimal point & will store 123.4 If entered 123456, the value of a will be 12345 [ ~ 12345.00 ]

With printf, we would be able to control how many characters can be printed after decimal as well.

printf( "%5.2f \n", a );

The value of 123.4 will be printed as 12.30 [ total 5, including the decimal & 2 digits after decimal ] But this have a limitation, where if the digits in the value are more than 5, it will display the actual value.

eg: The value of 123456.7, will be displayed as 123456.70.

This [ specifying the no. of digits after the decimal, as mentioned for printf ] I heard can be used for scanf as well, I am not sure sure & the compiler I use doesn't support that format. Verify whether your compiler does.

Now, when it comes to taking data from an external interface, are you talking about serialization here, I mean transmission of data on netwrok. Then, to my knowledge your approach is fine. We generally tend to read in the form of char only, to make sure the application works for any format of data.

Narendra N