P: n/a

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  
Share this Question
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;
}  
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 FloatingPoint
Arithmetic" http://docs.sun.com/source/8063568/ncg_goldberg.html  
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  
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
nonconstant 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]  
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 crossposted 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  
P: n/a

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  
P: n/a

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 FloatingPoint
Arithmetic" http://docs.sun.com/source/8063568/ncg_goldberg.htm
What do you mean David? Is ther a solution for this?
Thanks.
Regards,
md  
P: n/a

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  
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  
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 lccwin 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/~lccwin32  
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 lccwin 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  
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 lccwin 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/~lccwin32  
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());  
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 lccwin 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.  
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 crossposted 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++  
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 lccwin 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/~lccwin32  
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.  
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/~lccwin32  
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 ?  
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/~lccwin32  
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  
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 crossposted 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  
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 crossposted 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 lccwin.
Lccwin gives you the best of C and C++

jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique http://www.cs.virginia.edu/~lccwin32  
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 crossposted 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  
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 crossposted 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/~lccwin32  
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 crossposted 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  
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  
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/~lccwin32  
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  
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?  
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/~lccwin32  
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/~lccwin32  
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  
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 inmemory 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.  
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 1e21 (if I counted
correctly). Those values can't be accurately represented with
double precision.
You can't go beyond 1e16, 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/~lccwin32  
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 inmemory 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/~lccwin32  
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 1e21 (if I counted
correctly). Those values can't be accurately represented with
double precision.
Nor can 0.3.
>
You can't go beyond 1e16, 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  
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?  
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 1e21 (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  
P: n/a

jacob navia wrote:
Who cares?
That works in lccwin.
Lccwin 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.  
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 1e21 (if I counted correctly). Those values can't be accurately represented with double precision.
Nor can 0.3.
>You can't go beyond 1e16, 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/~lccwin32  
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 1e21 (if I counted correctly). Those values can't be accurately represented with double precision.
Nor can 0.3.
>>You can't go beyond 1e16, 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  
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 implementationdefined 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.  
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 implementationdefined 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/~lccwin32  
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/(r0.3);
printf("%Lf\n",r);
}
$ ./a.out
0.300000
89984117432729520.078125
Works great.  
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 1e21 (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/~lccwin32  
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/~lccwin32  
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 copypasted 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'  
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.   This discussion thread is closed Replies have been disabled for this discussion.   Question stats  viewed: 9669
 replies: 206
 date asked: Nov 22 '07
