7

Is there a way to do this without using the stream? For example, something like this:

double a = 6.352356663353535;
double b = a.precision(5);

instead of:

double a = 6.352356663353535;
std::cout.precision(5);
std::cout << a << std::endl;

I am new to C++ and I am curious. Thanks, in advance.

programmingNoob
  • 141
  • 2
  • 3
  • 8
  • To clarify, I assume that after the first example `std::cout << b << std::endl;` should produce the same output as the second example does? – MSalters Sep 10 '12 at 11:31
  • No, for the first example, double b was there to reduce a to 5 sig. fig, whereas in the second example there is no need for that variable. – programmingNoob Sep 10 '12 at 13:19
  • That was why I inquired about the **output**. You're confused about the internal representation, obviously, so I was wondering what you expected to see on the outside. – MSalters Sep 10 '12 at 14:25
  • Yes, I was wanting to get a number to 5.s.f. I am now wondering whether it is possible to get a string from the stream, and if so, how to do it with the second example. – programmingNoob Sep 10 '12 at 14:55

3 Answers3

7

I've revised the code taking into account @john, @Konrad and @KennyTM's suggestions. I've check that it works with negative numbers.

#include <cmath>
#include <cstdio>
using namespace std;
int main()
{
   double a = 6.352356663353535;
   double  intpart;
   double fractpart = modf (a, &intpart);
   fractpart  = roundf(fractpart * 100000.0)/100000.0; // Round to 5 decimal places
   double b = intpart + fractpart;
   printf("%.5lf", b);
}

Outputs

6.35236
Phillip Ngan
  • 15,482
  • 8
  • 63
  • 79
  • You should use function `floor` not a cast to long which might overflow. `double b = floor(a*10000.0)/10000.0;` (and probably use `ceil` for -ve numbers). – john Sep 10 '12 at 10:36
  • 3
    The question was about C++: please don’t use legacy headers in your answer. – Konrad Rudolph Sep 10 '12 at 10:53
  • @KonradRudolph I'm new to all this terminology, sorry; what is a 'legacy header'? – programmingNoob Sep 10 '12 at 11:02
  • @DereckKachere: One should use cmath and cstdio instead of math.h and stdio.h. – Macke Sep 10 '12 at 11:20
  • Why don't you just use `roundf`? – kennytm Sep 10 '12 at 11:43
  • @KonradRudolph is not legacy it is C standard header. specifies float and long double overloads where C language can not have overloads. – Öö Tiib Sep 10 '12 at 11:55
  • 1
    @ÖöTiib From C’s perspective it’s not legacy but we’re talking about C++ here, where it *is*, see C.2. (“their use is deprecated in C++”). Furthermore, `` *does* provide the overloads in C++ (D.5). – Konrad Rudolph Sep 10 '12 at 12:00
  • @KennyTM Do you mean `std::round` (sorry but it fits the current discussion)? And besides that `roundf` is for `float`, anyway. Othwerwise you're right, in C++11 there isn't any need for manual round to even anymore – Christian Rau Sep 10 '12 at 12:13
  • @ÖöTiib - when used in C++, the standard C headers do have overloaded versions. As they do in C, through some serious hackery (see >). And, although they are deprecated in C++, that was a triumph of jingoism in the original C++ standard and has no actual significance. – Pete Becker Sep 10 '12 at 12:49
5

doubles are almost universally implemented as IEEE floating point numbers. Their precision depends on the number size only (in the case of double, which is short for “double-precision floating point number”, it’s 53 bits). There is no way of manually setting the precision of a floating point number.

The display precision is always a property of the output formatting, never of the number. Don’t try to change the number via rounding, the operation makes no sense. You don’t need to reduce a number’s precision, except for display purposes.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    IEEE-754 is common, but not required. – MSalters Sep 10 '12 at 12:02
  • 1
    @MSalters But making this clear makes the answer more complex without adding significant value. Nevertheless, I’ve added a small caveat. – Konrad Rudolph Sep 10 '12 at 12:09
  • Well, there are real IBM machines which have hardware for decimal floating point. On those, you can in fact zero a number of trailing digits in the mantissa. – MSalters Sep 10 '12 at 12:29
  • @KonradRudolph could you please look at this question and provide your opinion? Thousand of thanks https://stackoverflow.com/questions/44999495/c-display-12digit-double-or-int-as-full-instead-of-3-23223e9 – Wei Jul 09 '17 at 19:17
0

A double always has the same internal precision (most probably 53 bits of binary precision), no matter what you do. It is only when writing out the double as text in decimal form where you can control the decimal precision of the output. So no, you cannot set the precision of a binary double precision number to anything else than it's native precision (let aside a decimal precision).

If all you want is round a number to a given number of decimal digits, then consult Phillip's answer (but with the ammendments that john and Konrad made in their comments, of course). But note that this doesn't change the preicision of the underlying type and all computations with this number will be performed in binary double precision. Also such a rounded decimal number doesn't need to be represented exactly in the underlying binary floating point type.

If you really want to perform exact decimal arithmetic, then you have to look for third-party libraries providing actual decimal floating point types.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185