Decimal rounding function

B

Bubba

Greetings to all,

I'm searching for cheap, quick and easy rounding function in C, but (there
had to be but!) without any libraries. In other words, is there a sane
mathematical (or any other, for that matter) way that can be implemented
in C and round arbitrary number of decimal places them to desired decimal
places?

So, basically, something like this:

double round (double number, unsigned decimalPlaces) {
/* some magic here */ }

Basic point is to make it portable for everything from Motorola 68000 to
embedded ARM or latest gaming x64 CPU.

I tried doing it myself but couldn't even begin being puzzled about
determining number of decimal places in the first place, let alone doing
any rounding with them.

Also did some Googling research but found only solutions with strings and
similar tricks (which I was acquainted with) or written in C++. Appreciate
any help or hint.

TIA!
 
S

Seebs

I'm searching for cheap, quick and easy rounding function in C, but (there
had to be but!) without any libraries. In other words, is there a sane
mathematical (or any other, for that matter) way that can be implemented
in C and round arbitrary number of decimal places them to desired decimal
places?

Steal code from a library which does this. BSD libc has a working one (some
versions may still have bugs) which you can embed in nearly anything.

-s
 
B

Ben Bacarisse

Bubba said:
I'm searching for cheap, quick and easy rounding function in C, but (there
had to be but!) without any libraries. In other words, is there a sane
mathematical (or any other, for that matter) way that can be implemented
in C and round arbitrary number of decimal places them to desired decimal
places?

So, basically, something like this:

double round (double number, unsigned decimalPlaces) {
/* some magic here */ }

Just a word of warning: the exact answer is often not representable so
you might be surprised by the result. It all depends on what you are
doing with it.

<snip>
 
K

Keith Thompson

Bubba said:
Greetings to all,

I'm searching for cheap, quick and easy rounding function in C, but (there
had to be but!) without any libraries. In other words, is there a sane
mathematical (or any other, for that matter) way that can be implemented
in C and round arbitrary number of decimal places them to desired decimal
places?

So, basically, something like this:

double round (double number, unsigned decimalPlaces) {
/* some magic here */ }

Basic point is to make it portable for everything from Motorola 68000 to
embedded ARM or latest gaming x64 CPU.

I tried doing it myself but couldn't even begin being puzzled about
determining number of decimal places in the first place, let alone doing
any rounding with them.

Also did some Googling research but found only solutions with strings and
similar tricks (which I was acquainted with) or written in C++. Appreciate
any help or hint.

(The name "round" is already taken.)

There's no such function in the standard, and few such functions
floating (ahem) around out there, because it's really not as useful
as you might think.

Rounding a floating-point to a specified number of decimal places is
useful only if you're producing a string representation of the number.
(Well, there might be *some* use for it, but I can't think of any.)
And if you're doing that, you might as well just produce the string
directly.

round(1.375, 1) should give you 1.4, but 1.4 cannot be represented
exactly in binary floating-point. You might get something like
1.399999999999999911182158029987476766109466552734375, which depending
on how you print it, might come out as "1.3".

What are you really trying to accomplish? What do you intended to
do with the rounded number once you've generated it? Why not just
keep it in full precision until you're ready to truncate it when
printing it or converting it to a string?
 
B

Boon

Seebs said:
Steal code from a library which does this. BSD libc has a working one (some
versions may still have bugs) which you can embed in nearly anything.

Yours is a poor choice of words.

Taking code from BSD-licensed software is not "stealing" in any way.
 
B

Boon

Bubba said:
I'm searching for cheap, quick and easy rounding function in C, but (there
had to be but!) without any libraries. In other words, is there a sane
mathematical (or any other, for that matter) way that can be implemented
in C and round arbitrary number of decimal places them to desired decimal
places?

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

Willem

Malcolm McLean wrote:
) As Keith pointed out, important cases like 0.1 have no exact representation
) in typical binary-based floating point formats.
) So the thing to do is to use double, then do all your calcuations in whole
) integers. So if you work to 3 decimal palces, everything is multiplied by
) 1000. Don't be tempted to use long or int. For this purpose, you'll find
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
) double is the best integer type.

Why is that ?

) Note that multiplications and divisions need to be scaled.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
F

Flash Gordon

Willem said:
Malcolm McLean wrote:
) As Keith pointed out, important cases like 0.1 have no exact representation
) in typical binary-based floating point formats.
) So the thing to do is to use double, then do all your calcuations in whole
) integers. So if you work to 3 decimal palces, everything is multiplied by
) 1000. Don't be tempted to use long or int. For this purpose, you'll find
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
) double is the best integer type.

Why is that ?

He might be thinking of size. If long is 4 bytes and double is 8 (not
unusual) then you actually have more range of integers (with a step of
1) in a double than a long. Of course, the C99 type long long is likely
to be better if you need the range as it is 8 bytes for the integer
part! I have seen pre-long-long code which uses this technique successfully.
 
S

Seebs

Yours is a poor choice of words.

No, it's an intentional one.
Taking code from BSD-licensed software is not "stealing" in any way.

Actualy, it can be, if you don't pay attention to the fine details of the
licensing, but basically agreed.

But "steal" has a long-standing usage in software as a synonym for
"repurpose". As in, yanking a little bit of code from something else and
using it in a new context. I find this usage amusing. I do not consider
it particularly technically precise, but it's idiomatic.

-s
 
K

Keith Thompson

Malcolm McLean said:
integer types do implicit rounding towards zero, which often needs to be
handled very carefully. (The whole point is to keep the precision). Also
they typically have less range than a double. Then a double degrades
gracefully on overflow, which is most likely what you want. Also you'll use
fewer casts converting between your special representation and the ultimate
normal real representations you'll probably use.

You're making a lot of unsupported assumptions about what the OP wants
to do.

To state the obvious, double is not an integer type. Dividing an odd
number by 2.0 gives you a non-integer. Computing a result beyond
the range of integer values that the type can represent exactly
(typically around 53 bits or so) loses precision. In both cases,
this happens silently. Is this what the OP wants? If so, how did
you reach this conclusion based on the fact that the OP wants a
decimal rounding function?
 
F

Flash Gordon

Malcolm said:
Most people want to accumulate the error.

That is a very big assumption. In a lot of financial applications you
are specifically required (sometimes by law) to *not* accumulate error.
So holding the calculations in
double and then calling floor(x + 0.5) to get the result to 3 decimal places
(in scaled arithmetic) is probably what he wants. Wanting to round towards
zero and throw away the errors, which is what will happen if you use
integers, is an unusual thing to want.

You are making big assumptions on the application domain based on no
knowledge. There are lots of possible reasons to not want to do that.
 
F

Flash Gordon

Malcolm said:
Most people want to accumulate the error.

That is a very big assumption. In a lot of financial applications you
are specifically required (sometimes by law) to *not* accumulate error.
So holding the calculations in
double and then calling floor(x + 0.5) to get the result to 3 decimal places
(in scaled arithmetic) is probably what he wants. Wanting to round towards
zero and throw away the errors, which is what will happen if you use
integers, is an unusual thing to want.

You are making big assumptions on the application domain based on no
knowledge. There are lots of possible reasons to not want to do that.
 
N

Nobody

To state the obvious, double is not an integer type.

It is capable of exactly representing many integers, often with more bits
than any C90 integer type.
Dividing an odd
number by 2.0 gives you a non-integer.

Using integers, dividing an odd number by two gives you an incorrect
result.
Computing a result beyond
the range of integer values that the type can represent exactly
(typically around 53 bits or so) loses precision.

The equivalent situation with an integer type results in a much larger
error (overflow).
In both cases, this happens silently.

Integer overflow and truncation are both silent, and not easy to test for.
With doubles, both of these can be easily tested for afterwards. Also, in
C99 you may be able to trap an inexact result.
 
K

Keith Thompson

Nobody said:
It is capable of exactly representing many integers, often with more bits
than any C90 integer type.

Yes. It's still not an integer type.
Using integers, dividing an odd number by two gives you an incorrect
result.

That depends on what result you wanted. For example, if I want the
index of an element at the middle of an array, if (min+max)/2 gives me
7.5 that's not very useful; I really want 7.
The equivalent situation with an integer type results in a much larger
error (overflow).


Integer overflow and truncation are both silent, and not easy to test for.
With doubles, both of these can be easily tested for afterwards. Also, in
C99 you may be able to trap an inexact result.

Both double and long int, for example, can be used to represent
integers. Both are imperfect representations of the infinite set of
mathematical integers; whichever one you choose, you'll have to work
around some problems. There are some cases where a floating-point
type is the best choice, but I don't think they're particularly
common. (Malcolm McLean was arguing that double is the right choice,
with very little basis for that assumption.)
 
F

Flash Gordon

Malcolm said:
In which case you'll want to call floor(x + 0.5) explictly to make it
obvious that ypu are throwing away the errors at the points designated by
law. Just leaving it to implied rounding in integer arithmetic is inviting a
visit from the serious fraud office.

No, it isn't inviting a visit by the SFO. I like a few others here
actually get paid to work on software that does financial calculations,
in my case including calculating certain types of tax.

We do a lot of calculations using a scaled long, and we always know what
we are doing in terms of rounding. Some of the software predates long
long being a common extension, so it tends to use double when we need an
integer type larger than 32 bits, but that means we have to be a *lot*
more careful than we would using an integer type. An integer type would
(in our case) give an obviously wrong result when it does not work,
double gives a subtly wrong result, which is MUCH more likely to get us
in trouble.
 
N

Nick Keighley

"Keith Thompson" ha scritto nel messaggio


i will save it
why?

but not in the string reppresentation (because that number
has to be used)

what for?
because the result of computation has to be round

why? and what does "round" mean?

The usual reason for "rounding" something is that you're going to show
it to a person.
 
N

Nick Keighley

your quoting style is very odd


"Nick Keighley" <[email protected]> ha scritto nel messaggio



what for?



why? and what does "round" mean?

The usual reason for "rounding" something is that you're going to show
it to a person.

....or a financial calculation

#it is only my hobby program for doing operations like what does
#our bank to our account

ah. Money. I'd expect a bank accoun to round to the penny (cent). This
is a t least good enough for a toy program. Why not just store the
number of pennies (cents)? No floating point needed.
#i can consider one bank account; each operation on that account has to
#be saved in the round form (because each operation *has* to do its rounding).
#it has to be saved because that number should be used

#for what "round" mean...
#for example i consider the C language round mode function for unsigned:
#[that round is round(number, 0)]
#round(x.x0x1x2x3x4x5x6...xn,  2) mean:
#find the machine reppresentation y more near to the number
# x.x0x10000000000000...
#or better find the machine representation y of the number
# x.x0x10000000000000..
#with "|y-x.x0x100000000...|<e=0.0000...0001"
#where "e" dipend from the fixed point number representation

all sounds a bit complicated for a simple bank account emulator
 
B

bartc

Nick said:
...or a financial calculation



ah. Money. I'd expect a bank accoun to round to the penny (cent). This
is a t least good enough for a toy program. Why not just store the
number of pennies (cents)? No floating point needed.

Try working out percentages (eg. VAT, interest) using just whole pennies.
 
N

Nick Keighley

I disagree.  There are lots of reasons for rounding, especially in
commerce, that don't have to involve "showing it to a person".  The
"showing it to a person" rounding can usually be accomplished with
formats in the *printf family of functions.  Explicit rounding is
mostly used for other reasons.

<snip many reasons for rounding>

consider me suitably refuted
 
B

bartc

Keith Thompson said:
Rounding a floating-point to a specified number of decimal places is
useful only if you're producing a string representation of the number.
(Well, there might be *some* use for it, but I can't think of any.)
And if you're doing that, you might as well just produce the string
directly.

The long thread 'Rounding double' from Nov 22 2007 gave quite a few reasons
why rounding to decimal places might be useful.
round(1.375, 1) should give you 1.4, but 1.4 cannot be represented
exactly in binary floating-point. You might get something like
1.399999999999999911182158029987476766109466552734375, which depending
on how you print it, might come out as "1.3".

If you sent binary 1.39999... to a machine which used it to place a mark on
a rod calibrated in inches and tenths of an inch, the mark will be placed at
the 1.4" mark, as near as can be measured. And maybe these marks are only
needed at 0.1" spacing so you don't want it at 1.375".
What are you really trying to accomplish? What do you intended to
do with the rounded number once you've generated it? Why not just
keep it in full precision until you're ready to truncate it when
printing it or converting it to a string?

The human world /does/ use decimal arithmetic so rounding to decimals does
make sense, and it needn't be confined to string representations (although
that seemed to be the overwhelming view in that other long thread too).

Anyway if you are transmitting, in binary, a number known only to be
accurate to 2 decimals, how do you ensure that the final string
representation (if any) will only use 2 decimals? You might otherwise get
nonsense displayed.

(For that matter, if a certain number can clearly only be a whole number,
yet is transmitted in floating point (eg. to a function), it makes sense to
round to a whole number first; ie. do round(x,0). Otherwise any noise in the
number can cause problems. And round(x,0) is little different to
round(x,1)).
 

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

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top