By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
428,978 Members | 1,467 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 428,978 IT Pros & Developers. It's quick & easy.

Rounding double

P: n/a
md
Hi

Does any body know, how to round a double value with a specific number
of digits after the decimal points?

A function like this:

RoundMyDouble (double &value, short numberOfPrecisions)

It then updates the value with numberOfPrecisions after the decimal
point.

Any help is appreciated.

Thanks.
md
Nov 22 '07 #1
Share this Question
Share on Google+
206 Replies


P: n/a
On Nov 22, 10:39 am, md <mojtaba.da...@gmail.comwrote:
Hi

Does any body know, how to round a double value with a specific number
of digits after the decimal points?

A function like this:

RoundMyDouble (double &value, short numberOfPrecisions)
{
int p = pow(10, numberOfPrecisions);
value = (int)(value * p + 0.5) / (double)p;
}
Nov 22 '07 #2

P: n/a
On Wed, 21 Nov 2007 21:39:57 -0800 (PST) in comp.lang.c++, md
<mo***********@gmail.comwrote,
>Hi

Does any body know, how to round a double value with a specific number
of digits after the decimal points?

A function like this:

RoundMyDouble (double &value, short numberOfPrecisions)
You cannot in general round a double value to a specific number of
digits, because doubles are not decimal. Save your rounding 'til you
are ready to format the number into a decimal string.

See "What Every Computer Scientist Should Know About Floating-Point
Arithmetic" http://docs.sun.com/source/806-3568/ncg_goldberg.html

Nov 22 '07 #3

P: n/a
md said:
Hi

Does any body know, how to round a double value with a specific number
of digits after the decimal points?

A function like this:

RoundMyDouble (double &value, short numberOfPrecisions)

It then updates the value with numberOfPrecisions after the decimal
point.
Well, you have a syntax error right there: double &value isn't legal. You
presumably meant double *value.

Elsethread, you were given this suggestion (suitably modified so that it
will actually compile, and with a driver added):

#include <stdio.h>
#include <math.h>

void RoundMyDouble (double *value, short numberOfPrecisions)

{
int p = pow(10, numberOfPrecisions);
*value = (int)(*value * p + 0.5) / (double)p;
}

int main(void)
{
double v = 3.14159265358979323846;
short int ndp = 0;
while(ndp < 10)
{
double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.16f, \"rounded\" to %hd decimals, is %.16f\n",
v,
ndp++,
newv);
}

return 0;
}

Here are the test results:

3.1415926535897931, "rounded" to 0 decimals, is 3.0000000000000000
3.1415926535897931, "rounded" to 1 decimals, is 3.1000000000000001
3.1415926535897931, "rounded" to 2 decimals, is 3.1400000000000001
3.1415926535897931, "rounded" to 3 decimals, is 3.1419999999999999
3.1415926535897931, "rounded" to 4 decimals, is 3.1415999999999999
3.1415926535897931, "rounded" to 5 decimals, is 3.1415899999999999
3.1415926535897931, "rounded" to 6 decimals, is 3.1415929999999999
3.1415926535897931, "rounded" to 7 decimals, is 3.1415926999999999
3.1415926535897931, "rounded" to 8 decimals, is 3.1415926500000002
3.1415926535897931, "rounded" to 9 decimals, is -2.1474836480000001

As you can see, it doesn't really round at all. It nudges the value close
to what is required, but doesn't hit the requirement right on the nose.
And that last result looks like a lot of fun, doesn't it? :-)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #4

P: n/a
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:v9******************************@bt.com...
md said:
>Hi

Does any body know, how to round a double value with a specific number
of digits after the decimal points?

A function like this:

RoundMyDouble (double &value, short numberOfPrecisions)

It then updates the value with numberOfPrecisions after the decimal
point.

Well, you have a syntax error right there: double &value isn't legal. You
presumably meant double *value.
Actually, double& value is legal in C++ but not C. It declares value as a
non-constant reference. It is not legal in C however. This was cross posted
to two newsgroups (c.l.c++ and c.l.c) which is usually a bad idea just for
this problem.

[snip rest of reply]
Nov 22 '07 #5

P: n/a
Jim Langston said:
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:v9******************************@bt.com...
>>
Well, you have a syntax error right there: double &value isn't legal.
You presumably meant double *value.

Actually, double& value is legal in C++ but not C.
Right - but of course a cross-posted article should "work" in all the
groups into which it's posted. Here, the post worked in clc++ but not in
clc, so either it should not have been posted to clc or the pointer syntax
should have been used rather than the reference syntax (at which point, of
course, there would have been howls of protest from the clc++ crowd, and
perhaps rightly so).
This was cross
posted to two newsgroups (c.l.c++ and c.l.c) which is usually a bad idea
just for this problem.
Indeed.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #6

P: n/a
md
On Nov 22, 6:21 pm, Richard Heathfield <r...@see.sig.invalidwrote:
md said:
Hi
Does any body know, how to round a double value with a specific number
of digits after the decimal points?
A function like this:
RoundMyDouble (double &value, short numberOfPrecisions)
It then updates the value with numberOfPrecisions after the decimal
point.

Well, you have a syntax error right there: double &value isn't legal. You
presumably meant double *value.

Elsethread, you were given this suggestion (suitably modified so that it
will actually compile, and with a driver added):

#include <stdio.h>
#include <math.h>

void RoundMyDouble (double *value, short numberOfPrecisions)

{
int p = pow(10, numberOfPrecisions);
*value = (int)(*value * p + 0.5) / (double)p;

}

int main(void)
{
double v = 3.14159265358979323846;
short int ndp = 0;
while(ndp < 10)
{
double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.16f, \"rounded\" to %hd decimals, is %.16f\n",
v,
ndp++,
newv);
}

return 0;

}

Here are the test results:

3.1415926535897931, "rounded" to 0 decimals, is 3.0000000000000000
3.1415926535897931, "rounded" to 1 decimals, is 3.1000000000000001
3.1415926535897931, "rounded" to 2 decimals, is 3.1400000000000001
3.1415926535897931, "rounded" to 3 decimals, is 3.1419999999999999
3.1415926535897931, "rounded" to 4 decimals, is 3.1415999999999999
3.1415926535897931, "rounded" to 5 decimals, is 3.1415899999999999
3.1415926535897931, "rounded" to 6 decimals, is 3.1415929999999999
3.1415926535897931, "rounded" to 7 decimals, is 3.1415926999999999
3.1415926535897931, "rounded" to 8 decimals, is 3.1415926500000002
3.1415926535897931, "rounded" to 9 decimals, is -2.1474836480000001

As you can see, it doesn't really round at all. It nudges the value close
to what is required, but doesn't hit the requirement right on the nose.
And that last result looks like a lot of fun, doesn't it? :-)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Yes, Richard. That is the result I also got.
Sorry for sending the message to two different groups.

Can some one give a solution for how to solve this problem?

Thanks again
md
Nov 22 '07 #7

P: n/a
md
On Nov 22, 4:56 pm, David Harmon <sou...@netcom.comwrote:
On Wed, 21 Nov 2007 21:39:57 -0800 (PST) in comp.lang.c++, md
<mojtaba.da...@gmail.comwrote,
Hi
Does any body know, how to round a double value with a specific number
of digits after the decimal points?
A function like this:
RoundMyDouble (double &value, short numberOfPrecisions)

You cannot in general round a double value to a specific number of
digits, because doubles are not decimal. Save your rounding 'til you
are ready to format the number into a decimal string.

See "What Every Computer Scientist Should Know About Floating-Point
Arithmetic" http://docs.sun.com/source/806-3568/ncg_goldberg.htm
What do you mean David? Is ther a solution for this?
Thanks.

Regards,
md
Nov 22 '07 #8

P: n/a
md
On Nov 22, 4:49 pm, suresh <mail2msur...@gmail.comwrote:
On Nov 22, 10:39 am, md <mojtaba.da...@gmail.comwrote:Hi
Does any body know, how to round a double value with a specific number
of digits after the decimal points?
A function like this:
RoundMyDouble (double &value, short numberOfPrecisions)

{
int p = pow(10, numberOfPrecisions);
value = (int)(value * p + 0.5) / (double)p;

}- Hide quoted text -

- Show quoted text -
I tried that before but it does not work!

md
Nov 22 '07 #9

P: n/a
md said:
Does any body know, how to round a double value with a specific number
of digits after the decimal points?
<snip>
>
Yes, Richard. That is the result I also got.
Sorry for sending the message to two different groups.

Can some one give a solution for how to solve this problem?
It has already been explained to you that this simply can't be done (in
general). Let's take a frinstance, and pi/10 is as good as anything else
for this purpose:

0.314159265358989323846...

and you want to round it to 6 decimal places. So you want the value of the
double to be precisely 0.314159.

Let's see how we might represent such a number, using pure binary notation.
(Floating point numbers aren't actually stored in pure binary, but it's
not all /that/ different, it's the same underlying problem, and this one
is easier to explain and easier to follow.)

In pure binary notation, we use a binary point rather than a decimal point
("radix point" is an umbrella term that covers them both, and others). The
column to the immediate left of the binary point is worth 1. Every column
to the right of the binary point is worth half as much as its immediate
left neighbour. Thus, 0.5 (decimal) is 0.1 (binary), 0.25 (decimal) is
0.01 (binary), 0.75 (decimal) is 0.11 (binary), and so on.

So how do we represent EXACTLY 0.314159 in pure binary notation? How many
bits do you think we'll need?

0.1 = 1/2 = 0.5 - too large
0.01 = 1/4 = 0.25 - too small
0.011 = 3/8 = 0.375 - too large
0.0101 = 5/16 = 0.3125 - too small
0.01011 = 11/32 = 0.34375 - too large
0.010101 = 21/64 = 0.328125 - too large
0.0101001 = 41/128 = 0.3203125 - too large
0.01010001 = 81/256 = 0.31640625 - too large
0.010100001 = 161/512 = 0.314453125 - too large
0.0101000001 = 321/1024 = 0.3134765625 - too small
0.01010000011 = 643/2048 = 0.31396484375 - too small
0.010100000111 = 1287/4096 = 0.314208984375 - too large
0.0101000001101 = 2573/8192 = 0.3140869140625 - too small
0.01010000011011 = 5147/16384 = 0.31414794921875 - too small
0.010100000110111 = 10295/32768 = 0.314178466796875 - too large
0.0101000001101101 = 20589/65536 = 0.3141632080078125 - too large

Sixteen bits so far, and we're not even close.

So instead of trying to do the impossible, just round the displayed value
rather than the stored value. For example, if you want to display pi/10 to
six places, just do this: printf("%.6f\n", pi/10);

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #10

P: n/a
md wrote:
On Nov 22, 4:49 pm, suresh <mail2msur...@gmail.comwrote:
>On Nov 22, 10:39 am, md <mojtaba.da...@gmail.comwrote:Hi
>>Does any body know, how to round a double value with a specific number
of digits after the decimal points?
A function like this:
RoundMyDouble (double &value, short numberOfPrecisions)
{
int p = pow(10, numberOfPrecisions);
value = (int)(value * p + 0.5) / (double)p;

}- Hide quoted text -

- Show quoted text -

I tried that before but it does not work!

md
This can go beyond 9:
#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

int main(void)
{
long double v = 3.1415926535897932384626L;
short int ndp = 0;
while(ndp < 20)
{
long double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.21Lf, \"rounded\" to %hd decimals, is %.21Lf\n",
v,
ndp++,
newv);
}

return 0;
}

You will need a modern C compiler to use this (C99 standard).
Using lcc-win I get:
3.1415926535897932390: 0 decimals 3.0000000000000000000
3.1415926535897932390: 1 decimals 3.1000000000000000000
3.1415926535897932390: 2 decimals 3.1400000000000000000
3.1415926535897932390: 3 decimals 3.1420000000000000000
3.1415926535897932390: 4 decimals 3.1416000000000000000
3.1415926535897932390: 5 decimals 3.1415900000000000000
3.1415926535897932390: 6 decimals 3.1415930000000000000
3.1415926535897932390: 7 decimals 3.1415927000000000000
3.1415926535897932390: 8 decimals 3.1415926500000000000
3.1415926535897932390: 9 decimals 3.1415926540000000000
3.1415926535897932390: 10 decimals 3.1415926536000000000
3.1415926535897932390: 11 decimals 3.1415926535900000000
3.1415926535897932390: 12 decimals 3.1415926535900000000
3.1415926535897932390: 13 decimals 3.1415926535898000000
3.1415926535897932390: 14 decimals 3.1415926535897900000
3.1415926535897932390: 15 decimals 3.1415926535897930000
3.1415926535897932390: 16 decimals 3.1415926535897932000
3.1415926535897932390: 17 decimals 3.1415926535897932400
3.1415926535897932390: 18 decimals 3.1415926535897932390
3.1415926535897932390: 19 decimals 1.0000000000000000000

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #11

P: n/a
jacob navia said:

<snip>
#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

int main(void)
{
long double v = 3.1415926535897932384626L;
short int ndp = 0;
while(ndp < 20)
{
long double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.21Lf, \"rounded\" to %hd decimals, is %.21Lf\n",
v,
ndp++,
newv);
}

return 0;
}

You will need a modern C compiler to use this (C99 standard).
Using lcc-win I get:
<snip>
>3.1415926535897932390: 19 decimals 1.0000000000000000000
Do you think that's a compiler bug, or a programmer bug?

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #12

P: n/a
Richard Heathfield wrote:
jacob navia said:

<snip>
>#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

int main(void)
{
long double v = 3.1415926535897932384626L;
short int ndp = 0;
while(ndp < 20)
{
long double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.21Lf, \"rounded\" to %hd decimals, is %.21Lf\n",
v,
ndp++,
newv);
}

return 0;
}

You will need a modern C compiler to use this (C99 standard).
Using lcc-win I get:
<snip>
>>3.1415926535897932390: 19 decimals 1.0000000000000000000

Do you think that's a compiler bug, or a programmer bug?
output of gcc:
3.1415926535897932385: 0 decimals 3.0000000000000000000
[snip]
3.1415926535897932385: 17 decimals 3.1415926535897932400
3.1415926535897932385: 18 decimals 3.1415926535897932389
3.1415926535897932385: 19 decimals 1.0000000000000000000

If it is a compiler bug, it is a shared compiler bug.

It isn't a programmer bug either. Long long has a finite
number of decimal digits as you may know.

18.
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #13

P: n/a
jacob navia wrote:
md wrote:
>On Nov 22, 4:49 pm, suresh <mail2msur...@gmail.comwrote:
>>On Nov 22, 10:39 am, md <mojtaba.da...@gmail.comwrote:Hi

Does any body know, how to round a double value with a specific
number of digits after the decimal points?
A function like this:
RoundMyDouble (double &value, short numberOfPrecisions)
{
int p = pow(10, numberOfPrecisions);
value = (int)(value * p + 0.5) / (double)p;

}- Hide quoted text -

- Show quoted text -

I tried that before but it does not work!

md

This can go beyond 9:
#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}
I have floor(). It even goes past 11!
--
IYesNo yes=YesNoFactory.getFactoryInstance().YES;
yes.getDescription().equals(array[0].toUpperCase());
Nov 22 '07 #14

P: n/a
jacob navia wrote:
Richard Heathfield wrote:
>jacob navia said:

<snip>
>>#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

int main(void)
{
long double v = 3.1415926535897932384626L;
short int ndp = 0;
while(ndp < 20)
{
long double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.21Lf, \"rounded\" to %hd decimals, is %.21Lf\n",
v,
ndp++,
newv);
}

return 0;
}

You will need a modern C compiler to use this (C99 standard).
Using lcc-win I get:
<snip>
>>>3.1415926535897932390: 19 decimals 1.0000000000000000000

Do you think that's a compiler bug, or a programmer bug?

output of gcc:
3.1415926535897932385: 0 decimals 3.0000000000000000000
[snip]
3.1415926535897932385: 17 decimals 3.1415926535897932400
3.1415926535897932385: 18 decimals 3.1415926535897932389
3.1415926535897932385: 19 decimals 1.0000000000000000000

If it is a compiler bug, it is a shared compiler bug.

It isn't a programmer bug either. Long long has a finite
number of decimal digits as you may know.
Which makes use of long long a programming error. You should have used
one of the rounding functions like floorl(), nearbyintl(), rintl(), or
roundl(), instead of conversion to long long. Even with that fix, the
algorithm you choose needlessly results in overflow (or underflow, for
negative values of numberOfPrecisions) in some cases.

I say that it's needless (and therefore a programming error) because you
can avoid both problems by using sprintf() and sscanf(). There are more
efficient ways of doing it, but that one is sufficient.
Nov 22 '07 #15

P: n/a
On Thu, 22 Nov 2007 09:12:02 +0000 in comp.lang.c++, Richard
Heathfield <rj*@see.sig.invalidwrote,
>Right - but of course a cross-posted article should "work" in all the
groups into which it's posted.
But saying that "double &value" is illegal doesn't "work" in c.l.c++
Nov 22 '07 #16

P: n/a
James Kuyper wrote:
jacob navia wrote:
>Richard Heathfield wrote:
>>jacob navia said:

<snip>

#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

int main(void)
{
long double v = 3.1415926535897932384626L;
short int ndp = 0;
while(ndp < 20)
{
long double newv = v;
RoundMyDouble(&newv, ndp);
printf("%.21Lf, \"rounded\" to %hd decimals, is %.21Lf\n",
v,
ndp++,
newv);
}

return 0;
}

You will need a modern C compiler to use this (C99 standard).
Using lcc-win I get:

<snip>

3.1415926535897932390: 19 decimals 1.0000000000000000000

Do you think that's a compiler bug, or a programmer bug?

output of gcc:
3.1415926535897932385: 0 decimals 3.0000000000000000000
[snip]
3.1415926535897932385: 17 decimals 3.1415926535897932400
3.1415926535897932385: 18 decimals 3.1415926535897932389
3.1415926535897932385: 19 decimals 1.0000000000000000000

If it is a compiler bug, it is a shared compiler bug.

It isn't a programmer bug either. Long long has a finite
number of decimal digits as you may know.

Which makes use of long long a programming error.
Why?
I get 18 digits, and this is more than enough for double precision
that gives 16 digits at best!
You should have used
one of the rounding functions like floorl(), nearbyintl(), rintl(), or
roundl(), instead of conversion to long long. Even with that fix, the
algorithm you choose needlessly results in overflow (or underflow, for
negative values of numberOfPrecisions) in some cases.
I did not choose any algorithm. It was proposed by somebody else,
and I merely adapted it to give enough decimal digits for
double precision. Note that I did NOT change the cast in the
denominator of the division from double to long double.

I say that it's needless (and therefore a programming error) because you
can avoid both problems by using sprintf() and sscanf(). There are more
efficient ways of doing it, but that one is sufficient.
And this one is sufficient for double precision too.
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #17

P: n/a
jacob navia wrote:
James Kuyper wrote:
....
>Which makes use of long long a programming error.

Why?
I get 18 digits, and this is more than enough for double precision
that gives 16 digits at best!
That assertion depends upons unportable (and more importantly,
unnecessary) assumptions about the width of long long and the precision
of long double.
Nov 22 '07 #18

P: n/a
James Kuyper wrote:
jacob navia wrote:
>James Kuyper wrote:
...
>>Which makes use of long long a programming error.

Why?
I get 18 digits, and this is more than enough for double precision
that gives 16 digits at best!

That assertion depends upons unportable (and more importantly,
unnecessary) assumptions about the width of long long and the precision
of long double.
Probably. Your solution is always the best since you did not
propose any

:-)
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #19

P: n/a
jacob navia wrote:
James Kuyper wrote:
>jacob navia wrote:
>>If it is a compiler bug, it is a shared compiler bug.

It isn't a programmer bug either. Long long has a finite
number of decimal digits as you may know.

Which makes use of long long a programming error.

Why?
I get 18 digits, and this is more than enough for double precision
that gives 16 digits at best!
I'm curious. What does your machine print for 6.0221415e23 ?
Nov 22 '07 #20

P: n/a
Marco Manfredini wrote:
jacob navia wrote:
>James Kuyper wrote:
>>jacob navia wrote:
>>>If it is a compiler bug, it is a shared compiler bug.

It isn't a programmer bug either. Long long has a finite
number of decimal digits as you may know.

Which makes use of long long a programming error.

Why?
I get 18 digits, and this is more than enough for double precision
that gives 16 digits at best!

I'm curious. What does your machine print for 6.0221415e23 ?
The same as 6.0221415e23+0.5

Interesting no?
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #21

P: n/a
jacob navia wrote:
Marco Manfredini wrote:
>jacob navia wrote:
>>James Kuyper wrote:
jacob navia wrote:
>>>>If it is a compiler bug, it is a shared compiler bug.
>
It isn't a programmer bug either. Long long has a finite
number of decimal digits as you may know.

Which makes use of long long a programming error.

Why?
I get 18 digits, and this is more than enough for double precision
that gives 16 digits at best!

I'm curious. What does your machine print for 6.0221415e23 ?

The same as 6.0221415e23+0.5

Interesting no?
I mean when it comes out of RoundMyDouble

Nov 22 '07 #22

P: n/a
David Harmon said:
On Thu, 22 Nov 2007 09:12:02 +0000 in comp.lang.c++, Richard
Heathfield <rj*@see.sig.invalidwrote,
>>Right - but of course a cross-posted article should "work" in all the
groups into which it's posted.

But saying that "double &value" is illegal doesn't "work" in c.l.c++
Touche'. :-) Nevertheless, agreeing that it's legal doesn't work in clc.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #23

P: n/a
Richard Heathfield wrote:
David Harmon said:
>On Thu, 22 Nov 2007 09:12:02 +0000 in comp.lang.c++, Richard
Heathfield <rj*@see.sig.invalidwrote,
>>Right - but of course a cross-posted article should "work" in all the
groups into which it's posted.
But saying that "double &value" is illegal doesn't "work" in c.l.c++

Touche'. :-) Nevertheless, agreeing that it's legal doesn't work in clc.
Who cares?

That works in lcc-win.

Lcc-win gives you the best of C and C++

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #24

P: n/a
jacob navia said:
Richard Heathfield wrote:
>David Harmon said:
>>On Thu, 22 Nov 2007 09:12:02 +0000 in comp.lang.c++, Richard
Heathfield <rj*@see.sig.invalidwrote,
Right - but of course a cross-posted article should "work" in all the
groups into which it's posted.
But saying that "double &value" is illegal doesn't "work" in c.l.c++

Touche'. :-) Nevertheless, agreeing that it's legal doesn't work in clc.

Who cares?
People who don't wish to mislead to OP by giving incorrect advice.

<spam snipped>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #25

P: n/a
Richard Heathfield wrote:
jacob navia said:
>Richard Heathfield wrote:
>>David Harmon said:

On Thu, 22 Nov 2007 09:12:02 +0000 in comp.lang.c++, Richard
Heathfield <rj*@see.sig.invalidwrote,
Right - but of course a cross-posted article should "work" in all the
groups into which it's posted.
But saying that "double &value" is illegal doesn't "work" in c.l.c++
Touche'. :-) Nevertheless, agreeing that it's legal doesn't work in clc.
Who cares?

People who don't wish to mislead to OP by giving incorrect advice.

<spam snipped>
Incorrect advice happens only when they read your posts.

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #26

P: n/a
jacob navia said:
Richard Heathfield wrote:
>jacob navia said:
>>Richard Heathfield wrote:
David Harmon said:

On Thu, 22 Nov 2007 09:12:02 +0000 in comp.lang.c++, Richard
Heathfield <rj*@see.sig.invalidwrote,
>Right - but of course a cross-posted article should "work" in all
>the groups into which it's posted.
But saying that "double &value" is illegal doesn't "work" in c.l.c++
Touche'. :-) Nevertheless, agreeing that it's legal doesn't work in
clc.

Who cares?

People who don't wish to mislead [the] OP by giving incorrect advice.

<spam snipped>

Incorrect advice happens only when they read your posts.
Wrong again. I'm not going to argue this point with you, however. If anyone
is silly enough to believe you, that's their problem.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #27

P: n/a
In article <fi**********@aioe.org>, jacob navia <ja***@nospam.orgwrote:
>Richard Heathfield wrote:
>jacob navia said:
>>Who cares?
>People who don't wish to mislead to OP by giving incorrect advice.
>Incorrect advice happens only when they read your posts.
Incorrect advice also happens when people read some of *my* posts,
so your "only" would appear to be incorrect.

I don't know of -any- poster here who has a perfect advice posting
record (though some average much higher quality than others.)
--
"No one has the right to destroy another person's belief by
demanding empirical evidence." -- Ann Landers
Nov 22 '07 #28

P: n/a
Walter Roberson wrote:
In article <fi**********@aioe.org>, jacob navia <ja***@nospam.orgwrote:
>Richard Heathfield wrote:
>>jacob navia said:
>>>Who cares?
>>People who don't wish to mislead to OP by giving incorrect advice.
>Incorrect advice happens only when they read your posts.

Incorrect advice also happens when people read some of *my* posts,
so your "only" would appear to be incorrect.

I don't know of -any- poster here who has a perfect advice posting
record (though some average much higher quality than others.)
And there are others that do not give ANY solution,
limiting themselves to say why the solutions presented in some
cases not asked for would not work

I used the original solution and fixed it for double
precision, it is surely not the best solution.

But instead of proposing a better solution this people limit
to talking nonsense without ever proposing anything else.

Then I get angry start getting mad at heathfield and this
degrades.

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #29

P: n/a
jacob navia said:
Walter Roberson wrote:
>In article <fi**********@aioe.org>, jacob navia <ja***@nospam.org>
wrote:
>>Richard Heathfield wrote:
jacob navia said:
>>>>Who cares?
>>>People who don't wish to mislead to OP by giving incorrect advice.
>>Incorrect advice happens only when they read your posts.

Incorrect advice also happens when people read some of *my* posts,
so your "only" would appear to be incorrect.

I don't know of -any- poster here who has a perfect advice posting
record (though some average much higher quality than others.)

And there are others that do not give ANY solution,
Instead, they have given appropriate explanations of why no solution to the
question as asked is possible, and suggestions as to how to deal with this
problem, which is inherent in the general representation of fractions.
limiting themselves to say why the solutions presented in some
cases not asked for would not work
The question as asked is: "Does any body know, how to round a double value
with a specific number of digits after the decimal points?" No specific
cases were asked for, so any criticism of any broken "solution", if it
addresses any cases at all, is bound to address cases not asked for.
I used the original solution and fixed it for double
precision, it is surely not the best solution.
That, at least, is true. The best solution is to understand the inherent
limitations in representing fractions, and to recognise that the
appropriate way to deal with this is to deal with the rounding at the
display stage.
But instead of proposing a better solution this people limit
to talking nonsense without ever proposing anything else.
Ah, we're back to "nonsense" as your synonym for "correct solution that
Jacob Navia doesn't understand", are we?
Then I get angry start getting mad at heathfield and this
degrades.
If you get angry every time you're wrong, you must be angry a *lot*. But
the degradation comes from your posting of incorrect solutions and
misconceptions about C. If you were to take the trouble to learn C
properly, you might find yourself winning more arguments (and getting the
support of others in this newsgroup, instead of constantly facing their
corrections).

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #30

P: n/a
jacob navia wrote:
James Kuyper wrote:
....
Probably. Your solution is always the best since you did not
propose any
?
I suggesting using sprintf() and sscanf(). I left the details to be
worked out by the reader. Was that too obscure a hint for you?
Nov 22 '07 #31

P: n/a
Richard Heathfield wrote:
>
That, at least, is true. The best solution is to understand the inherent
limitations in representing fractions, and to recognise that the
appropriate way to deal with this is to deal with the rounding at the
display stage.
That wasn't what the OP asked. He wanted to round it without any
display, maybe to be used in further calculation or whatever.

And it IS possible to round correctly a double precision
number. One of the possible solutions is:

#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long double fv=fabsl(*value);
if (fv 1e17)
return ;
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

This is quite awful, but it works (with 64 bit long long and
wider precision long double)
>But instead of proposing a better solution this people limit
to talking nonsense without ever proposing anything else.

Ah, we're back to "nonsense" as your synonym for "correct solution that
Jacob Navia doesn't understand", are we?
Nonse means to tell the OP that what he is asking is
impossible!
>Then I get angry start getting mad at heathfield and this
degrades.
I think is the pompous tone that makes me nervous.

"Ex cathedra"...
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #32

P: n/a
James Kuyper wrote:
jacob navia wrote:
>James Kuyper wrote:
...
>Probably. Your solution is always the best since you did not
propose any

?
I suggesting using sprintf() and sscanf(). I left the details to be
worked out by the reader. Was that too obscure a hint for you?
But he was asking for a function that returns a double, not
asking about PRINTING a double.

Maybe he wants to WRITE printf :-)

Or you are saying that you belive this is impossible
in C???

double roundto(double n,int digits);

I do not believe so. OK. My solution looks (and is horrible,
but it has the merit of working for a wide range:
#include <math.h>

double RoundMyDouble (long double *value, short numberOfPrecisions)

{
long double fv=fabsl(*value);
if (fv 1e17 ) // That could be replaced with some standard constant
return ;
long long p = powl(10.0L, numberOfPrecisions);
return (long long)(*value * p + 0.5L) / (long double)p;
}

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #33

P: n/a
jacob navia said:
Richard Heathfield wrote:
>>
That, at least, is true. The best solution is to understand the inherent
limitations in representing fractions, and to recognise that the
appropriate way to deal with this is to deal with the rounding at the
display stage.

That wasn't what the OP asked. He wanted to round it without any
display, maybe to be used in further calculation or whatever.
And it was demonstrated that this can't be done in general, so his
requirement cannot be met in general.
And it IS possible to round correctly a double precision
number.
Show me 0.33 rounded to one decimal place.
One of the possible solutions is:

#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long double fv=fabsl(*value);
if (fv 1e17)
return ;
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

This is quite awful, but it works (with 64 bit long long and
wider precision long double)
For 0.33 rounded to one decimal place with this code of yours, I get a
result of 0.300000000000000000011, which is clearly wrong (it should be
0.3).

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #34

P: n/a
jacob navia wrote:
James Kuyper wrote:
>jacob navia wrote:
>>James Kuyper wrote:
...
>>Probably. Your solution is always the best since you did not
propose any

?
I suggesting using sprintf() and sscanf(). I left the details to be
worked out by the reader. Was that too obscure a hint for you?

But he was asking for a function that returns a double, not
asking about PRINTING a double.
OK - so my hint WAS too obscure. Think about it a little while before
you respond again. I'm sure you can figure it out with a little extra
thought. In particular, think about the implications of the fact that I
specified sprintf() rather than printf(), and sscanf() instead of scanf().

Incidentally, the sprintf()/sscanf() combination is unnecessarily
inefficient. One loop writes to a buffer, and another loop reads from
it, and both loops spends time dealing with possibilities that don't
apply in this context. It's possible to remove the buffer by extracting
the loops from from sprintf() and sscanf(), simplifying them, and
connecting them directly together. However, that's a significantly more
complicated solution, and I wouldn't recommend attempting it unless you
do in-memory rounding to a specified number of decimal digits
frequently. I can't remember ever needing that capability. I round to a
specified number of decimal digits only in my outputs.
Or you are saying that you belive this is impossible
in C???
I wouldn't have provided a hint how to solve the problem, if I'd thought
that solving the problem was impossible. I'm not a sadist.
Nov 22 '07 #35

P: n/a
Richard Heathfield wrote:
Show me 0.33 rounded to one decimal place.
>One of the possible solutions is:

#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long double fv=fabsl(*value);
if (fv 1e17)
return ;
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

This is quite awful, but it works (with 64 bit long long and
wider precision long double)

For 0.33 rounded to one decimal place with this code of yours, I get a
result of 0.300000000000000000011, which is clearly wrong (it should be
0.3).
This is perfectly OK since double has only 16 decimal digits,
and the first ones in your result appear at 1e-21 (if I counted
correctly). Those values can't be accurately represented with
double precision.

You can't go beyond 1e-16, since DBL_DIG is 15.

Writing it in in a more sensible way:

double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #36

P: n/a
James Kuyper wrote:
jacob navia wrote:
>James Kuyper wrote:
>>jacob navia wrote:
James Kuyper wrote:
...
Probably. Your solution is always the best since you did not
propose any

?
I suggesting using sprintf() and sscanf(). I left the details to be
worked out by the reader. Was that too obscure a hint for you?

But he was asking for a function that returns a double, not
asking about PRINTING a double.

OK - so my hint WAS too obscure. Think about it a little while before
you respond again. I'm sure you can figure it out with a little extra
thought. In particular, think about the implications of the fact that I
specified sprintf() rather than printf(), and sscanf() instead of scanf().

Incidentally, the sprintf()/sscanf() combination is unnecessarily
inefficient. One loop writes to a buffer, and another loop reads from
it, and both loops spends time dealing with possibilities that don't
apply in this context. It's possible to remove the buffer by extracting
the loops from from sprintf() and sscanf(), simplifying them, and
connecting them directly together. However, that's a significantly more
complicated solution, and I wouldn't recommend attempting it unless you
do in-memory rounding to a specified number of decimal digits
frequently. I can't remember ever needing that capability. I round to a
specified number of decimal digits only in my outputs.
>Or you are saying that you belive this is impossible
in C???

I wouldn't have provided a hint how to solve the problem, if I'd thought
that solving the problem was impossible. I'm not a sadist.
double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}

Supposing long double is extended precision, why should this not
work?

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #37

P: n/a
jacob navia said:
Richard Heathfield wrote:
<snip>
>For 0.33 rounded to one decimal place with this code of yours, I get a
result of 0.300000000000000000011, which is clearly wrong (it should be
0.3).

This is perfectly OK since double has only 16 decimal digits,
and the first ones in your result appear at 1e-21 (if I counted
correctly). Those values can't be accurately represented with
double precision.
Nor can 0.3.
>
You can't go beyond 1e-16, since DBL_DIG is 15.

Writing it in in a more sensible way:

double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}
Could someone else please share with us the result they get when they drive
this function with inputs of 0.33 and 1 ? I'm getting some very, very
strange results here.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #38

P: n/a
jacob navia wrote:
double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}

Supposing long double is extended precision, why should this not
work?
Suppose long double is 128 bit and long long 64 bit. Why should this work?

Nov 22 '07 #39

P: n/a
jacob navia wrote, On 22/11/07 23:01:
Richard Heathfield wrote:
>Show me 0.33 rounded to one decimal place.
>>One of the possible solutions is:

#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long double fv=fabsl(*value);
if (fv 1e17)
return ;
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

This is quite awful, but it works (with 64 bit long long and
wider precision long double)

For 0.33 rounded to one decimal place with this code of yours, I get a
result of 0.300000000000000000011, which is clearly wrong (it should
be 0.3).

This is perfectly OK
It does not meet the OPs requirements as specified.
since double has only 16 decimal digits,
and the first ones in your result appear at 1e-21 (if I counted
correctly). Those values can't be accurately represented with
double precision.
<snip>

Which is precisely the problem. If it is wanted for display then there
are better ways, if it is wanted for further calculations then it is
very important that the OP understand why it is not possible in general.
--
Flash Gordon
Nov 22 '07 #40

P: n/a
jacob navia wrote:
Who cares?
That works in lcc-win.
Lcc-win gives you the best of C and C++
This is a very bad answer, and precisely what you should /not/ have said
if you wanted to be taken seriously.

Nov 22 '07 #41

P: n/a
Richard Heathfield wrote:
jacob navia said:
>Richard Heathfield wrote:

<snip>
>>For 0.33 rounded to one decimal place with this code of yours, I get a
result of 0.300000000000000000011, which is clearly wrong (it should be
0.3).
This is perfectly OK since double has only 16 decimal digits,
and the first ones in your result appear at 1e-21 (if I counted
correctly). Those values can't be accurately represented with
double precision.

Nor can 0.3.
>You can't go beyond 1e-16, since DBL_DIG is 15.

Writing it in in a more sensible way:

double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}

Could someone else please share with us the result they get when they drive
this function with inputs of 0.33 and 1 ? I'm getting some very, very
strange results here.
d:\lcc\mc68\test>type tdouble3.c
#include <stdio.h>
#include <float.h>
#include <math.h>

double roundto(long double value, unsigned digits)

{
long double fv = fabs(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value;
long long p = powl(10.0L, digits);
return roundl(p*value)/p;
}

int main(int argc,char *argv[])
{
long double v = atof(argv[1]);
short int ndp = 0;
while(ndp < DBL_DIG)
{
long double newv = v;
newv = roundto(newv, ndp);
printf("%.19Lf: %hd decimals %.16Lf\n",
v,
ndp++,
newv);
}

return 0;
}

d:\lcc\mc68\test>tdouble3 0.33
0.3300000000000000160: 0 decimals 0.0000000000000000
0.3300000000000000160: 1 decimals 0.3000000000000000
0.3300000000000000160: 2 decimals 0.3300000000000000
0.3300000000000000160: 3 decimals 0.3300000000000000
0.3300000000000000160: 4 decimals 0.3300000000000000
0.3300000000000000160: 5 decimals 0.3300000000000000
0.3300000000000000160: 6 decimals 0.3300000000000000
0.3300000000000000160: 7 decimals 0.3300000000000000
0.3300000000000000160: 8 decimals 0.3300000000000000
0.3300000000000000160: 9 decimals 0.3300000000000000
0.3300000000000000160: 10 decimals 0.3300000000000000
0.3300000000000000160: 11 decimals 0.3300000000000000
0.3300000000000000160: 12 decimals 0.3300000000000000
0.3300000000000000160: 13 decimals 0.3300000000000000
0.3300000000000000160: 14 decimals 0.3300000000000000

d:\lcc\mc68\test>tdouble3 1
1.0000000000000000000: 0 decimals 1.0000000000000000
1.0000000000000000000: 1 decimals 1.0000000000000000
1.0000000000000000000: 2 decimals 1.0000000000000000
1.0000000000000000000: 3 decimals 1.0000000000000000
1.0000000000000000000: 4 decimals 1.0000000000000000
1.0000000000000000000: 5 decimals 1.0000000000000000
1.0000000000000000000: 6 decimals 1.0000000000000000
1.0000000000000000000: 7 decimals 1.0000000000000000
1.0000000000000000000: 8 decimals 1.0000000000000000
1.0000000000000000000: 9 decimals 1.0000000000000000
1.0000000000000000000: 10 decimals 1.0000000000000000
1.0000000000000000000: 11 decimals 1.0000000000000000
1.0000000000000000000: 12 decimals 1.0000000000000000
1.0000000000000000000: 13 decimals 1.0000000000000000
1.0000000000000000000: 14 decimals 1.0000000000000000

d:\lcc\mc68\test>

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #42

P: n/a
jacob navia said:
Richard Heathfield wrote:
>jacob navia said:
>>Richard Heathfield wrote:

<snip>
>>>For 0.33 rounded to one decimal place with this code of yours, I get a
result of 0.300000000000000000011, which is clearly wrong (it should
be 0.3).

This is perfectly OK since double has only 16 decimal digits,
and the first ones in your result appear at 1e-21 (if I counted
correctly). Those values can't be accurately represented with
double precision.

Nor can 0.3.
>>You can't go beyond 1e-16, since DBL_DIG is 15.

Writing it in in a more sensible way:

double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}

Could someone else please share with us the result they get when they
drive this function with inputs of 0.33 and 1 ? I'm getting some very,
very strange results here.
d:\lcc\mc68\test>type tdouble3.c
No, I said "someone else". I wouldn't trust you to make a cup of coffee,
let alone a computer program.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Nov 22 '07 #43

P: n/a
jacob navia wrote:
This is perfectly OK since double has only 16 decimal digits,
This is incorrect. The ISO standard requires a double to have at least
10 digits, but specifies no upper bound.

5.2.4.2.2 Characteristics of floating types
8. The values given in the following list shall be replaced by constant
expressions with implementation-defined values that are greater or equal
in magnitude (absolute value) to those shown, with the same sign:
FLT_DIG 6
DBL_DIG 10
LDBL_DIG 10

There are a couple of worked examples showing 15 digits, and one
footnote that references the ISO/IEC floating point standard, but
nothing else normative.
Nov 22 '07 #44

P: n/a
Mark McIntyre wrote:
jacob navia wrote:
>This is perfectly OK since double has only 16 decimal digits,

This is incorrect. The ISO standard requires a double to have at least
10 digits, but specifies no upper bound.

5.2.4.2.2 Characteristics of floating types
8. The values given in the following list shall be replaced by constant
expressions with implementation-defined values that are greater or equal
in magnitude (absolute value) to those shown, with the same sign:
FLT_DIG 6
DBL_DIG 10
LDBL_DIG 10

There are a couple of worked examples showing 15 digits, and one
footnote that references the ISO/IEC floating point standard, but
nothing else normative.
That "footnote" is Annex F, and it IS normative. I cite (again)

F.2 Types
1 The C floating types match the IEC 60559 formats as follows:
The float type matches the IEC 60559 single format.
The double type matches the IEC 60559 double format

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #45

P: n/a
Richard Heathfield wrote:
jacob navia said:
>Richard Heathfield wrote:
>>Could someone else please share with us the result they get when they
drive this function with inputs of 0.33 and 1 ? I'm getting some very,
very strange results here.
d:\lcc\mc68\test>type tdouble3.c

No, I said "someone else". I wouldn't trust you to make a cup of coffee,
let alone a computer program.
long double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}

int main()
{
long double r=roundto(0.33,1);
printf("%Lf\n",r);
r=1/(r-0.3);

printf("%Lf\n",r);
}

$ ./a.out
0.300000
89984117432729520.078125

Works great.
Nov 22 '07 #46

P: n/a
Flash Gordon wrote:
jacob navia wrote, On 22/11/07 23:01:
>Richard Heathfield wrote:
>>Show me 0.33 rounded to one decimal place.

One of the possible solutions is:

#include <stdio.h>
#include <math.h>

void RoundMyDouble (long double *value, short numberOfPrecisions)

{
long double fv=fabsl(*value);
if (fv 1e17)
return ;
long long p = powl(10.0L, numberOfPrecisions);
*value = (long long)(*value * p + 0.5L) / (double)p;
}

This is quite awful, but it works (with 64 bit long long and
wider precision long double)

For 0.33 rounded to one decimal place with this code of yours, I get
a result of 0.300000000000000000011, which is clearly wrong (it
should be 0.3).

This is perfectly OK

It does not meet the OPs requirements as specified.
>since double has only 16 decimal digits,
and the first ones in your result appear at 1e-21 (if I counted
correctly). Those values can't be accurately represented with
double precision.

<snip>

Which is precisely the problem. If it is wanted for display then there
are better ways, if it is wanted for further calculations then it is
very important that the OP understand why it is not possible in general.
OK from a teaching viewpoint maybe. But there IS a general solution
within a double precision framework. Of course due to the
nature of FP it is an approximation but so what? That is
floating point and there is no way around it.

Instead of saying "Impossible" we should give the best
approximation that is all.
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #47

P: n/a
Marco Manfredini wrote:
Richard Heathfield wrote:
>jacob navia said:
>>Richard Heathfield wrote:
Could someone else please share with us the result they get when they
drive this function with inputs of 0.33 and 1 ? I'm getting some very,
very strange results here.

d:\lcc\mc68\test>type tdouble3.c

No, I said "someone else". I wouldn't trust you to make a cup of
coffee, let alone a computer program.
long double roundto(long double value, unsigned digits)
{
This is not my function excuse me.

My function returned a double, NOT a long double.

AND THAT IS IMPORTANT!

Works great.
Yes. Works great.

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Nov 22 '07 #48

P: n/a
jacob navia wrote:
>Could someone else please share with us the result they get when they
drive this function with inputs of 0.33 and 1 ? I'm getting some very,
very strange results here.
d:\lcc\mc68\test>type tdouble3.c
I copy-pasted this exact code, and compiled under gcc 4.1.2:

thelinux clc_tests $ ./a.out 0.33
1374389535.0000000000000000000: 0 decimals 1374389535.0000000000000000
1374389535.0000000000000000000: 1 decimals 1374389535.0000000000000000

I'm giving this one a 'strange' score of 'high'

Nov 22 '07 #49

P: n/a
jacob navia wrote:
James Kuyper wrote:
>jacob navia wrote:
>>James Kuyper wrote:
jacob navia wrote:
James Kuyper wrote:
...
Probably. Your solution is always the best since you did not
propose any

?
I suggesting using sprintf() and sscanf(). I left the details to be
worked out by the reader. Was that too obscure a hint for you?

But he was asking for a function that returns a double, not
asking about PRINTING a double.

OK - so my hint WAS too obscure. Think about it a little while before
you respond again. I'm sure you can figure it out with a little extra
thought. In particular, think about the implications of the fact that
I specified sprintf() rather than printf(), and sscanf() instead of
scanf().
Have you given any more thought to my hint? If not, why did you quote it?

Note: Richard Heathfield has been saying this is impossible, I've been
saying it is possible. That's because we're referring to two different
things. It is impossible in binary floating point formats to represent
exactly an arbitrary floating point value rounded to a specified number
of decimal digits. That's simply because 10 is not a power of 2. That's
what Richard was talking about.

However, it is possible to calculate a result that is as close to the
ideally rounded value as is permitted by the precision of the floating
point type, which is what I'm talking about.
double roundto(long double value, unsigned digits)
{
long double fv=fabsl(value);
if (fv powl(10.0L,DBL_DIG) || digits DBL_DIG)
return value; // Out of range
long long p = powl(10.0L, digits);
return roundl(value * p ) / (double)p;
}

Supposing long double is extended precision, why should this not
work?
Well, it unnecessarily fails to work when digits is negative. I suppose
you could impose the arbitrary requirement digits >= 0, but the function
has an obvious meaning for digits<0, and that meaning is just as useful
as the meaning for digits >= 0 (which is not meant to imply that it's
particularly useful in either case).

Specifying that long double has extended precision is not sufficient,
even when digits>=0. A conforming implementation of C can use extended
precision for both double and long double, so long as __STDC_IEC559__ is
not #defined. In that case there's no guarantee that 'p' is big enough
to store the largest integer that can be stored in a double. As a
result, the rounded result will have less accuracy than it should.
Nov 22 '07 #50

206 Replies

This discussion thread is closed

Replies have been disabled for this discussion.