Rounding double

K

Kai-Uwe Bux

Richard said:
jacob navia said:



If your code has an error, however minor, then it is broken, in which case
I suggest you post a fixed version. The version you posted *does not work*
on my system. Quite apart from the fact that you are trying to solve an
impossible problem (the problem, remember, is that of rounding the value
of a double to a specified number of decimal places, which simply can't be
done), you are trying to solve it in a way that produces bizarrely
incorrect results on at least one system.

Hm. I wonder if this might be a matter of interpreting the problem.

The C standard says about sqrt() that it computed the nonnegative square
root. C++ inherits this requirement. If your interpretation of the rounding
problem is correct and if we transfer it to the other arithmetic
operations, then there can be no conforming implementations. In fact, even
elementary school arithmetic (+,-,*,/) cannot be done correctly under that
interpretation. However, that interpretation of the specs is not the only
possible.

A different interpretation of floating point computations is that an
operation (say multiplication, addition, sqrt, or rounding to a given
number of decimal places) should yield a double (or float or whatever types
are topical in the corresponding newsgroup) that is closest to the exact
mathematical result. If I recall correctly, this is by and large the
position taken by IEEE754.

When this (reasonable) interpretation is adopted, the problem of rounding to
a fixed number of decimals is solvable (and it is indeed not different from
any other computational problem). And if you don't adopt an interpretation
like that, floating point arithmetic in general is "impossible".


Best

Kai-Uwe Bux
 
J

jacob navia

Kai-Uwe Bux said:
Hm. I wonder if this might be a matter of interpreting the problem.

The C standard says about sqrt() that it computed the nonnegative square
root. C++ inherits this requirement. If your interpretation of the rounding
problem is correct and if we transfer it to the other arithmetic
operations, then there can be no conforming implementations. In fact, even
elementary school arithmetic (+,-,*,/) cannot be done correctly under that
interpretation. However, that interpretation of the specs is not the only
possible.

I am arguing precisely this since the beginning of this thread.
All trascendental functions, sqrt, pow, whatever. All of them yield
approximations of their real results.

The solution I proposed is surely not the best one but it is a first
try after a summary discussion here.

A different interpretation of floating point computations is that an
operation (say multiplication, addition, sqrt, or rounding to a given
number of decimal places) should yield a double (or float or whatever types
are topical in the corresponding newsgroup) that is closest to the exact
mathematical result. If I recall correctly, this is by and large the
position taken by IEEE754.

EXACTLY.

When this (reasonable) interpretation is adopted, the problem of rounding to
a fixed number of decimals is solvable (and it is indeed not different from
any other computational problem). And if you don't adopt an interpretation
like that, floating point arithmetic in general is "impossible".


Best

Kai-Uwe Bux


This is exactly my position.
 
R

Richard Heathfield

jacob navia said:

All trascendental functions, sqrt, pow, whatever. All of them yield
approximations of their real results.

Indeed, because finitely many bits cannot store the results precisely; and
this is why the OP's problem *as stated* has no solution. You are solving
a *different* problem (in a non-portable way).
 
P

Philip Potter

Richard said:
If it makes you any less disappointed, at least *someone* in this thread
has learned something. For one thing, I had no idea that the IEC 60559
stuff was in there. For another, having discovered that it was, I had no
idea that it was optional. So I've actually learned *two* things from this
thread, which pleases me greatly. (Whether I remember is another matter,
but I'll do my best.)

I think Jacob taught me those two facts not so long ago in exactly the
same way!
 
P

Philip Potter

Richard said:
Philip Potter said:
Richard Heathfield wrote:
I used the exact same code, except that I
read ahead in the thread and added <stdlib.h> as a result (I didn't get
a warning about atof because I had to switch off many diagnostics to get
the code to compile at all), and I also had to put braces around the
last two lines of roundto. I'm getting the following results:

me@here> ./foo 0.33
0.3300000000000000155: 0 decimals 256.0000000000000000
0.3300000000000000155: 1 decimals -21474836.0000000000000000
0.3300000000000000155: 2 decimals -20468203.0000000000000000
[...]
Have you any idea why this is happening?

Well, obviously I don't have a C99 compiler (I use gcc, which doesn't
conform to C99 yet), so to avoid changing the code too much I am forced to
rely on gcc extensions (which is why I had to turn off my usual collection
of diagnostic switches). It is possible that one or more of the extensions
don't operate according to C99 rules.

You may have noticed I used gcc too. I have no qualms about using
-std=c99 when I know it not to be fully-conformant; it appears you do.
This rapid accretion of irony over many such threads over several years has
now formed a solid irony cory so large that its gravityy is now having a
significant effect; not only has it attracted a lot of crusty, but it even
appears to have acquired an atmosphery.

"significanty effecty" surely? :)
 
P

Philip Potter

jacob said:
2: As you can see, my solution works in your machine. Either RH is not
telling the truth (unlikely) or he is using some minor error in the
code to trip about.

Given that you use long long and RH doesn't have a C99 compiler and
doesn't use -std=c99 on gcc, I don't think results on his (or even my)
machine are too meaningful.
3: It is interesting to note that you say that my solution doesn't
work when you see correct results in your machine.

Er, if you're referring to this:
...then I think it stands for itself. The reason your solution works is
because you use printf() to cut off the rounding error; RH's solution
used *exactly the same feature of printf()* to round.
 
P

Philip Potter

Richard said:
jacob navia said:


The compilation options shouldn't matter, but I'll tell you anyway:

No, they *do* matter. gcc is not a conforming C89, C95 or C99
implementation with no compilation options. With -ansi -pedantic, it's
quite a good C89 compiler. With -std=c99 -pedantic, it's a half-finished
C99 compiler.

I'm sure you know this already.
 
K

Kai-Uwe Bux

Richard said:
jacob navia said:



Indeed, because finitely many bits cannot store the results precisely; and
this is why the OP's problem *as stated* has no solution. You are solving
a *different* problem (in a non-portable way).

Well, telling the OP that his problem is unsolvable "as stated" could be a
good thing. Maybe he then just decides to report back to the customer and
the customer realizes that this was a stupid thing to ask for and everybody
is happy.

Another possible reaction of the OP is to not find that reply very helpful.
Maybe, he even thinks that you did not make an honest effort to interpret
his question correctly. Why would the OP want to know how to do X if a
moments thought tells you that doing X is impossible? Well, maybe he
doesn't know enough about floating point arithmetic to tell. But, maybe the
OP is not that uneducated and just gave an abbreviated description of the
problem (very much like the C standard where it requires that sqrt shall
compute the nonnegative square root of the argument).

When someone asks a question, the goal of interpretation is to figure out
what it is that this someone wants to know. I have the feeling that your
interpretation might fall short of reaching this goal. I do concede,
though, that we do not have much to go on.

It would be great if the OP could provide some more background as to _why_
he wants to round. For instance, it could be that he needs to comply with
accounting rules in his country which may require that certain values be
rounded to n decimals when transcribed from one table into another.
Depending on the purpose, your advice of postponing the problem until
output might be the right one; or it might be that the OP needs to use
decimal arithmetic instead of double to actually solve the hidden problem.


Best

Kai-Uwe Bux
 
M

Marco Manfredini

Kai-Uwe Bux said:
A different interpretation of floating point computations is that an
operation (say multiplication, addition, sqrt, or rounding to a given
number of decimal places) should yield a double (or float or whatever
types are topical in the corresponding newsgroup) that is closest to
the exact mathematical result. If I recall correctly, this is by and
large the position taken by IEEE754.

When this (reasonable) interpretation is adopted, the problem of
rounding to a fixed number of decimals is solvable (and it is indeed
not different from any other computational problem). And if you don't
adopt an interpretation like that, floating point arithmetic in
general is "impossible".

The problem with rounded numbers is that they have to be exact or else
the whole rounding is pointless. Rounding is done, because you want a
number whose relative error is 1) known 2) independent of the
representation and 3) it's operations gives the same result *no matter
what implementation of arithmetic operations you are using, given that
the result remains exact and representable*. If you have a bank account
you will acknowledge this - financial applications often have very
tight specifications on *how exactly* something has to be calculated,
when rounding must be done etc.

That's entirely different from working with trancedental numbers and
such which have no known representation anyway.

And actually, the problem is solvable with floating point. Multiply and
truncate, but omit the division and store the result with the decimal
designator in a struct { double value; int places; }. Voila, an exactly
rounded number. Now define arithmetic ops and go.
 
B

Bart

on my system. Quite apart from the fact that you are trying to solve an
impossible problem (the problem, remember, is that of rounding the value
of a double to a specified number of decimal places, which simply can't be
done)

Impossible? Rounding a floating point number to N decimals, or for
that matter any other interval such as 1/30, is possible and does have
uses other than simply printing the number.

Of course the result will be approximate because of the nature of
floating point, but will be billions of times more accurate than
doing no rounding because 'it can't be done'.

If I have a measurement X somewhere along a 1m stick (0.0 to 1.0) and
I want to find the nearest 10cm mark to X (eg X is 0.78, the nearest
will be 0.8), then it's clear than I can round 0.78 to 1 decimal (or
1/10) to get 0.8. The result, being stored in floating point binary,
may be out by a billionth of a micron or so. So what? My pencil mark
on the stick will not be that accurate.

The point is such a rounding can be done and has a useful purpose.

Bart
 
J

James Kuyper

Richard said:
jacob navia said:



Indeed, because finitely many bits cannot store the results precisely; and
this is why the OP's problem *as stated* has no solution. You are solving
a *different* problem (in a non-portable way).

It is quite possible that the OP was unaware of the fact that the
rounding could not be performed exactly. However, you cannot justify
assuming that he had that misconception just because he failed to
specify that he wanted the best available floating point approximation
to the rounded number. Leaving out the "best available approximation
...." wording in the expectation that it would be inferred by any
reasonable reader is the norm, not the exception, in such specifications.

The OP's follow-up messages have not clarified whether or not he was
aware of that issue when he posted the original message.
 
R

Richard Heathfield

Philip Potter said:
No, they *do* matter. gcc is not a conforming C89, C95 or C99
implementation with no compilation options. With -ansi -pedantic, it's
quite a good C89 compiler. With -std=c99 -pedantic, it's a half-finished
C99 compiler.

I'm sure you know this already.

Yes, it's a fair point. Okay, if I invoke gcc in conforming mode, the code
doesn't compile at all, for a number of reasons. (Clearly, to invoke gcc
in conforming mode means we have to go for C89 or, if you prefer, C90
conformance, since gcc doesn't have a C99 conforming mode.)
 
J

jacob navia

James said:
It is quite possible that the OP was unaware of the fact that the
rounding could not be performed exactly. However, you cannot justify
assuming that he had that misconception just because he failed to
specify that he wanted the best available floating point approximation
to the rounded number. Leaving out the "best available approximation
..." wording in the expectation that it would be inferred by any
reasonable reader is the norm, not the exception, in such specifications.

The OP's follow-up messages have not clarified whether or not he was
aware of that issue when he posted the original message.

In general, 100% exact results using floating point are impossible,
as you know very well.

Then, obviously, anyone asking here for the best rounding to n places
is asking for an approximation.

Suppose we get a question like:

"Please how can I calculate the square root of a number in C"

we all assume that it is about "the best floating point
approximation" and nobody would say "This problem
is impossible to solve as demonstrated by the greeks around
2000 years ago"

Nowhere did the OP say that he wanted 100% accuracy!

Now that Mr Heathfield sees that his position is completely untenable,
he starts modifying the original question, putting more words into the
OP than what he actually said.

I have argued since the beginning that the problem is solvable in
floating point in the usual floating pont manner, i.e. as an
approximation to the true result!
 
J

jacob navia

Richard said:
Philip Potter said:


Yes, it's a fair point. Okay, if I invoke gcc in conforming mode, the code
doesn't compile at all, for a number of reasons. (Clearly, to invoke gcc
in conforming mode means we have to go for C89 or, if you prefer, C90
conformance, since gcc doesn't have a C99 conforming mode.)

Can you stop all this theater?

Now compile with
gcc -std=c99 jn.c -lm

and tell me the results ok?

And if you do not want it do not compile it and shut up.
 
R

Richard Heathfield

Bart said:
Impossible? Rounding a floating point number to N decimals, or for
that matter any other interval such as 1/30, is possible and does have
uses other than simply printing the number.

Show me.
Of course the result will be approximate

But rounding is an operation that yields an exact result. 0.33, rounded to
one decimal place, is *precisely* 0.3, not 0.299999999999998 or
0.300000000000001 (no, I didn't count the 9s and 0s - I just held the key
down!). If the result is not exact, it isn't a rounding. It's merely an
approximation to a rounding.
because of the nature of
floating point, but will be billions of times more accurate than
doing no rounding because 'it can't be done'.

Oh, it can be done all right - it's just that it can't be done using
floating point. More precisely, you can't store 0.33 rounded to one
decimal place in a floating point number (unless you use a radix that
makes it possible, in which case there are other numbers you can't store).

If I have a measurement X somewhere along a 1m stick (0.0 to 1.0) and
I want to find the nearest 10cm mark to X (eg X is 0.78, the nearest
will be 0.8), then it's clear than I can round 0.78 to 1 decimal (or
1/10) to get 0.8.
Right.

The result, being stored in floating point binary,
may be out by a billionth of a micron or so. So what? My pencil mark
on the stick will not be that accurate.

Indeed, but the result will still be out.
The point is such a rounding can be done and has a useful purpose.

Yes, it can, but only by adopting a different representation. A double
simply can't cut it.
 
R

Richard Heathfield

James Kuyper said:
It is quite possible that the OP was unaware of the fact that the
rounding could not be performed exactly.

That is my belief, yes.
However, you cannot justify
assuming that he had that misconception just because he failed to
specify that he wanted the best available floating point approximation
to the rounded number.

On the other hand, answering *all* the questions people *don't* ask would
take infinite time. We're not mind readers.

If the OP is happy to take 0.2999999999999999999999998 as the result of
rounding 0.33 to one decimal place, that's fine - but he has not (yet)
said so.

<snip>
 
P

Philip Potter

Richard said:
Philip Potter said:


Yes, it's a fair point. Okay, if I invoke gcc in conforming mode, the code
doesn't compile at all, for a number of reasons. (Clearly, to invoke gcc
in conforming mode means we have to go for C89 or, if you prefer, C90
conformance, since gcc doesn't have a C99 conforming mode.)

So you take a C99 program (for I assume that is what it is since it uses
long long) and compile it with a C89 compiler, and complain when it
doesn't work?

Surely you know better than that?
 
R

Richard Heathfield

jacob navia said:

Nowhere did the OP say that he wanted 100% accuracy!

The OP said (and I'm quoting this for the *third* time): "Does any body
know, how to round a double value with a specific number of digits after
the decimal points?"

Thus, rounding 0.33 to one decimal place should result in a result with
*one* decimal place, not a couple of dozen decimal places.
Now that Mr Heathfield sees that his position is completely untenable,

On the contrary, I maintain that my position is not only tenable but the
best position to take on the available evidence.
he starts modifying the original question, putting more words into the
OP than what he actually said.

On the contrary, I have stuck to the original question, and have not read
into it the same unstated assumptions that some others (including you)
have been making.
 
R

Richard Heathfield

jacob navia said:
Richard Heathfield wrote:


Can you stop all this theater?

By "theater", presumably you mean my legitimate objections that the code
doesn't work on my system.
Now compile with
gcc -std=c99 jn.c -lm
Okay.

and tell me the results ok?

Okay.

cc1: unknown C standard `c99'

So - do you have a *portable* solution or don't you?
 
J

jacob navia

Richard said:
But rounding is an operation that yields an exact result. 0.33, rounded to
one decimal place, is *precisely* 0.3, not 0.299999999999998 or
0.300000000000001 (no, I didn't count the 9s and 0s - I just held the key
down!). If the result is not exact, it isn't a rounding. It's merely an
approximation to a rounding.


Oh, it can be done all right - it's just that it can't be done using
floating point. More precisely, you can't store 0.33 rounded to one
decimal place in a floating point number (unless you use a radix that
makes it possible, in which case there are other numbers you can't store).

We all know that Heathfield. O.3 is not representable,
so what?

We use the best approximation to it!

Pi is not representable nor "e" (the base of natural logarithms).

So WHAT?

We use the best approximation.

0.1 is not representable. SO WHAT?
We use the best approximation.

AND SO ON.

You go on and on repeating the same thing:

"Floating point numbers are an approximation, not the true result".

We all know that. That doesn't mean that approximations to the true
result are impossible, and that we can't give the OP an approximation
to the true result!
Indeed, but the result will still be out.

That is floating point! It is intrinsic to the nature of floating
point, and all your argumentation is just a boring remake
of the "floating point is always an approximation" mantra.
Yes, it can, but only by adopting a different representation. A double
simply can't cut it.

A double can have a precision of e-14 or e-15.
This allows to give the radius of the earth to a precision of a few
nanometers!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top