Rounding error, (100.0 * 9.95).to_i == 994

C

Carl Youngblood

Come to think of it, do all currencies even have "cents"? I know of
some countries where the currency is so devalued that nobody uses
fractionary amounts.
 
F

Francis Hwang

Well, it depends on what you're measuring. Some tasks need a finer
resolution than others. One example: A few years ago, one of the major
U.S. stock exhanges (NASDAQ, I think) went to a lot of trouble to
convert from expressing stock prices in fractions to expressing them in
pennies. Those prices used to be expressed as, for example, $16 3/4 or
$16 3/8 (down to 1/8 or 1/16, I think), now they're expressed as $16.75
or $16.33. (I don't think it goes finer than one cent.) This didn't
used to be a big deal, but there have been a lot of advances in trading
strategies and software that make it important now. If you have trading
instruments like options and futures to use, and you think the market
has valued a certain stock 2 cents too high or too low, you can make
that bet and clear a lot of money in one day.

On the other hand, all those traders living in New York don't think an
individual penny means anything. If they were late from work and saw a
penny on the street, they probably won't stop to pick it up. So
basically it depends on what you're measuring the money for in the
first place.
 
S

Steven Jenkins

trans. (T. Onoma) said:
I'm not claiming to be a mathematical expert. I have a fair grasp of many
concepts including floating-point arithmetic --but it's certainly not
perfect. I simply _believe_ that it can be done. That's my opinion, I may be
wrong, but I may also be right. You can have your opinion as well. But please
do not belittle my _attempt_. At least I'm trying a better world. An
introductory Computer Programming course in 1969 is certainly not the last
word on such matters.

No, the last word was J. H. Wilkinson, "Rounding Errors in Algebraic
Processes", 1963. :)

Look, T., no one's disrespecting you. But this particular problem has
been in the crosshairs of some very deep experts for 40 years. If you
want to try to beat them, be my guest. But don't claim that the
problem's been neglected, or that we don't understand how serious it is,
or that the prevailing industry standard is behind the times. There's a
lot of wisdom behind the way things are.

Steve
 
T

trans. (T. Onoma)

On Saturday 30 October 2004 02:44 pm, Lloyd Zusman wrote:
| The "better world" you are talking about already exists. I will explain
| that point below.
|
| People who understand the concepts of fixed-point and floating-point
| arithmetic would not expect the "to_i" operator to do _rounding_. That
| operation is defined as one which performs _truncation_. People who
| never learned these numerical concepts or who incorrectly expect
| truncation operators to do rounding should not be writing code to handle
| the navigation of Mars landers.

You misunderstand me then. I never expected that. The original message in this
thread asked about that, but this thread left that long ago and criss-crossed
with a second thread, in which we got on to a particular bugaboo...let me
find it... see ruby-talk:116739

| If someone wants the two floating-point numbers 100.00 and 9.95 to be
| multiplied together to yield the integer result 995, then rounding will
| _have to_ be performed. In order to do that, different procedures,
| other than (100.00 * 9.95).to_i, need to be used. For example, one of
| many ways to do it is this:
|
| irb(main):001:0> sprintf('%.0f', 100.00 * 9.95).to_i
| => 995
|
| That's because the "%f" format for sprintf is _defined_ as specifying
| that rounding gets done when it converts a floating-point number to its
| string representation. The to_i operator alone is not defined in that
| way.
|
| There are other algorithms and packages that already are in existence
| that will also perform rounding. In other words, we already live in
| this "better world". Someone who needs to use representations of
| decimal numbers that are forced into a fixed precision should learn that
| these various algorithms and packages exist, and they should learn how
| to make use of them.
|
| For example, see the "mathx" package in RAA. Also, see the BigDecimal
| and Rational packages, which already have been mentioned in this
| thread, I believe.

Yes, I'm aware of these. Thank you. If I were to sum up my point I think it
would be this: We are more than advanced enough to not have to use poor
representations of numbers that return obvious errors (as in the above given
alternate thread). Having to account for all the possible gotchas in variant
algorithms is a large waste. Yes, we had to deal with them for some time b/c
of technological restraints and learning curves, (and academic circles will
continue to explore them) but at this point it really shouldn't be turning up
in high level languages. As the example shows, we are not yet in this
particular "better world".

T.
 
T

trans. (T. Onoma)

| > I'm not claiming to be a mathematical expert. I have a fair grasp of many
| > concepts including floating-point arithmetic --but it's certainly not
| > perfect. I simply _believe_ that it can be done. That's my opinion, I may
| > be wrong, but I may also be right. You can have your opinion as well. But
| > please do not belittle my _attempt_. At least I'm trying a better world.
| > An introductory Computer Programming course in 1969 is certainly not the
| > last word on such matters.
|
| No, the last word was J. H. Wilkinson, "Rounding Errors in Algebraic
| Processes", 1963. :)

What happened to David Matula?

T.
 
L

Lloyd Zusman

trans. (T. Onoma) said:
On Saturday 30 October 2004 02:44 pm, Lloyd Zusman wrote:
| The "better world" you are talking about already exists. I will explain
| that point below.
|
| People who understand the concepts of fixed-point and floating-point
| arithmetic would not expect the "to_i" operator to do _rounding_. That
| operation is defined as one which performs _truncation_. People who
| never learned these numerical concepts or who incorrectly expect
| truncation operators to do rounding should not be writing code to handle
| the navigation of Mars landers.

You misunderstand me then. I never expected that. The original message
in this thread asked about that, but this thread left that long ago
and criss-crossed with a second thread, in which we got on to a
particular bugaboo...let me find it... see ruby-talk:116739

[ ... ]

Yes, I'm aware of these. Thank you. If I were to sum up my point I
think it would be this: We are more than advanced enough to not have
to use poor representations of numbers that return obvious errors (as
in the above given alternate thread). Having to account for all the
possible gotchas in variant algorithms is a large waste. Yes, we had
to deal with them for some time b/c of technological restraints and
learning curves, (and academic circles will continue to explore them)
but at this point it really shouldn't be turning up in high level
languages. As the example shows, we are not yet in this particular
"better world".

What technological constraints are you talking about? The constraints
that determine the rounding/truncation/etc. behavior of numbers in
computers are determined the nature of computers themselves: computers
do not have infinte memory. Therefore, any number that can be
represented in a computer, be it fixed point, floating point, rational,
or some other, possibly yet-to-be-defined format will _always_ be
subject to truncation, rounding, or other forms of approximation when it
is used in calculations. You can't get away from that.

The question, therefore, is not how to eliminate truncation or rounding,
but rather, how to intelligently perform these approximations when they
are necessary.

As Steven Jenkins has mentioned here, high-level research into numerical
methods is actively taking place, and it has been going on since
computers were invented ... actually, since before that time.

The problems you raise, if you think about them a bit, do not lend
themselves to simplistic solutions.

For example, explain to me an algorithm which will "properly" do
rounding in all of the following cases. How many decimal places will
the result have, and will there or will there not be any rounding?

1. 100 * 9.95

2. 100 * (29.85 / 3)

3. (100 * 29.850) / 3.0

6. 1 / 3

7. 1 / 3.0

8. 1 / sqrt(9)

etc. etc.

What is the intention of the programmer in each case, and what _should_
the answer be (in terms of number of decimal places, rounding behavior,
truncation behavior, etc.).
 
T

trans. (T. Onoma)

On Saturday 30 October 2004 04:31 pm, Lloyd Zusman wrote:
| For example, explain to me an algorithm which will "properly" do
| rounding in all of the following cases. How many decimal places will
| the result have, and will there or will there not be any rounding?

You first will have to specify the problem set better then that. For example
by 2 & 3 I take it you are making a distinction between integers and floats,
or are we just dealing with reals here and indifferent? If the former do you
wish the to coerce ints to floats or throw an error? Also what rounding?
--You didn't specify any percession, or what kind of draw option to use.
OTOH, maybe you believe these have to be rounded as is for the computer to
store the result. That's not so. I can represent the results of all these
calculations without rounding very easily.

| 1. 100 * 9.95
|
| 2. 100 * (29.85 / 3)
|
| 3. (100 * 29.850) / 3.0
|
| 6. 1 / 3
|
| 7. 1 / 3.0
|
| 8. 1 / sqrt(9)
|
| etc. etc.
|
| What is the intention of the programmer in each case, and what _should_
| the answer be (in terms of number of decimal places, rounding behavior,
| truncation behavior, etc.).

Did you read the alt thread? I'm not talking about variant viable behaviors,
depending on what one wants. I'm talking about what one should be able to
expect but doesn't get. I'll distill it for you, try:

(134.45 / (0.1)).round
(134.45 * (1.0/0.1)).round

T.
 
A

Aredridel

Well, it depends on what you're measuring. Some tasks need a finer
resolution than others. One example: A few years ago, one of the major
U.S. stock exhanges (NASDAQ, I think) went to a lot of trouble to
convert from expressing stock prices in fractions to expressing them in
pennies. Those prices used to be expressed as, for example, $16 3/4 or
$16 3/8 (down to 1/8 or 1/16, I think), now they're expressed as $16.75
or $16.33. (I don't think it goes finer than one cent.) This didn't
used to be a big deal, but there have been a lot of advances in trading
strategies and software that make it important now. If you have trading
instruments like options and futures to use, and you think the market
has valued a certain stock 2 cents too high or too low, you can make
that bet and clear a lot of money in one day.

On the other hand, all those traders living in New York don't think an
individual penny means anything. If they were late from work and saw a
penny on the street, they probably won't stop to pick it up. So
basically it depends on what you're measuring the money for in the
first place.

It's important when there's large amounts of a price -- a million at
one cent is surely much different than a million at a cent-and-a-half.
Fractional and decimal values are neccesary for some operations.

Also, traditionally, currency conversion is performed to the fourth
decimal, at least with the dollar.

Storing the currency along with the amount is important, too.
Supplying a current conversion table can be left as an excercise to
the reader, though.

Some currencies eschew fractions entirely. Some are not decimal. You
can't entirely get away with integers, though fixed-point precision is
a must for most financial calculations, and rational appropriate for
the rest. Floating-point inaccuracy is really annoying, and has
already bitten my in my financial app.
 
L

Lloyd Zusman

trans. (T. Onoma) said:
On Saturday 30 October 2004 04:31 pm, Lloyd Zusman wrote:
| For example, explain to me an algorithm which will "properly" do
| rounding in all of the following cases. How many decimal places will
| the result have, and will there or will there not be any rounding?

You first will have to specify the problem set better then that. For
example by 2 & 3 I take it you are making a distinction between
integers and floats, or are we just dealing with reals here and
indifferent? If the former do you wish the to coerce ints to floats or
throw an error? Also what rounding? --You didn't specify any
percession, or what kind of draw option to use. OTOH, maybe you
believe these have to be rounded as is for the computer to store the
result. That's not so. I can represent the results of all these
calculations without rounding very easily.

Let's specify all of the values to be floats in these examples.

Of course the results of the calculations I specified can be easily
represented in a number of textual formats. However, none of those
calculations can be done in floating point without precision being lost
and approximation being necessary.

Perhaps you are thinking of eliminating floating point and having the
computer use some other numerical representation ... like Rationals,
perhaps ... ???

| 1. 100 * 9.95
|
| 2. 100 * (29.85 / 3)
|
| 3. (100 * 29.850) / 3.0
|
| 6. 1 / 3
|
| 7. 1 / 3.0
|
| 8. 1 / sqrt(9)
|
| etc. etc.
|
| What is the intention of the programmer in each case, and what
| _should_ the answer be (in terms of number of decimal places,
| rounding behavior, truncation behavior, etc.).

Did you read the alt thread? I'm not talking about variant viable
behaviors, depending on what one wants. I'm talking about what one
should be able to expect but doesn't get. I'll distill it for you,
try:

(134.45 / (0.1)).round
(134.45 * (1.0/0.1)).round

Yes, I did read the alt thread, and therefore, to avoid confusion,
I'll stick with your example.

Using floating point numbers, there is no way to guarantee that all
pairs of calculations that fit the pattern in your example will yield
the same results. Sorry, but that's just the nature of the beast.

There is no floating point number that accurately represents 0.1. The
best you can get is an approximation. The second expression is written
to state that 1.0/0.1 is calculated _before_ the multiplication by
134.45. That's what the parentheses around that expression mean. This
division yields a result that only approximates 10.0, and therefore, the
result of the multiplication only approximates 1344.5

The only way this wouldn't happen would be for Ruby to evaluate the
second expression like this:

((134.45 * 1.0) / 0.1).round

But that's _different_ from what the original version of the statement
says (don't forget that parentheses are _defined_ in Ruby and most other
commonly used computer languages to specify the order of evaluation of
statement components).

Are you suggesting that Ruby should start ignoring the meaning of
parentheses and to evaluate statements differently from how they are
written?

It seems like you are trying to introduce a "do what I mean, not what I
say" aspect to Ruby. But how, in the general case, would Ruby know what
someone "means", if it ignores the strict instructions that the
programmer encodes via his/her use of parentheses and other language
constructs?

The goal you are trying for, if it's even possible, would have to be
achieved with something other than floating point arithmetic, which by
its very nature cannot guarantee that pairs of statements like the ones
you specified above will give precisely equivalent results.

Perhaps you should work on designing a new language that has
following characteristics:

1. No floating point arithmetic is done by default; rather, all
arithmetic involving values with decimal points is done with
something like Rationals, BigDecimals, etc. (although note that
rounding and truncation will still have to be done even in this
case, and there will be cases where precision is lost in ways that
are similar to the ones we've been discussing in this thread)

Perhaps this hypothetical language would convert decimal numbers to
rationals, as follows:

(134.45 * (1.0/0.1))
becomes: ((134 + (45/100)) * (1 / (1/10)))

This could be algebraicly reduced before anything is evaluated:

((134 + (45/100)) * (1 / (1/10)))
=> ((13400 + 45) * 10) / 100
=> (13445 / 10)
=> (2689 / 2)
=> 1344 + 1/2

Of course, how would you algebraicly reduce this statement
if the values of X, Y, and Z aren't known until run time?

(X * (Y/Z))

2. Parentheses around expressions are suggestions only and no longer
specify strict evaluation order.

For example, statement A might be transformed to statement B by the
compiler:

A. (134.45 * (1.0/0.1))
B. ((134.45 * 1.0) / 0.1)

But what would you do in this case?

(X * (Y/Z))

Should the order of evaluation be changed at run time, depending on
the values of X, Y, and Z at the time that the statement is
encountered? If so, what algorithm would you use for deciding when
and how to change the evaluation order?

3. etc.
 
T

trans. (T. Onoma)

| Using floating point numbers, there is no way to guarantee that all
| pairs of calculations that fit the pattern in your example will yield
| the same results. Sorry, but that's just the nature of the beast.

You are constraining the solution set to a system that can not provide a
solution --current float-pointing representation. It's tautological. My point
all along has been an _extension_ to the system to deal with the diffculties
you speak-of. Which is how floating-slash and SLI arithmetic came up. Also,
if you'll recall, Markus presented some points along the lines of my own
train of thought on such an extension.

| Of course the results of the calculations I specified can be easily
| represented in a number of textual formats. However, none of those
| calculations can be done in floating point without precision being lost
| and approximation being necessary.

Floating-point is a representation, no less, or more, than any other. The
differences lie in the pragmatics of application of that representation.
Roman numerals, for instance, generally suck for arithmetic production.
Floating-points are much better, of course, but they too have limitations --a
beastly nature, as you put it. Just becasue fp is modern does not mean that
there may not a another system that will be to fp as fp is to rn (so to
speak). And in fact, as I pointed out above, there are already some potential
candidates.

T.
 
L

Lloyd Zusman

trans. (T. Onoma) said:
| Using floating point numbers, there is no way to guarantee that all
| pairs of calculations that fit the pattern in your example will
| yield the same results. Sorry, but that's just the nature of the
| beast.

You are constraining the solution set to a system that can not provide
a solution --current float-pointing representation. It's
tautological. My point all along has been an _extension_ to the system
to deal with the diffculties you speak-of. Which is how floating-slash
and SLI arithmetic came up. Also, if you'll recall, Markus presented
some points along the lines of my own train of thought on such an
extension.

Yes, I recall.

Floating-point is a representation, no less, or more, than any
other. The differences lie in the pragmatics of application of that
representation. Roman numerals, for instance, generally suck for
arithmetic production. Floating-points are much better, of course,
but they too have limitations --a beastly nature, as you put it. Just
becasue fp is modern does not mean that there may not a another system
that will be to fp as fp is to rn (so to speak). And in fact, as I
pointed out above, there are already some potential candidates.

It's clear that you agree that we can't use floating point numbers to
achieve the goal that you mentioned. That's one of the main points of
the message of mine from which you culled the above quotes.

In that same message of mine, I offered two characteristics of a new,
hypothetical computer language which on the surface might appear to
provide a solution to the issues that you raise. What comments do you
have about these characteristics? I will repeat them here:

1. No floating point arithmetic is done by default; rather, all
arithmetic involving values with decimal points is done with
something like Rationals, BigDecimals, etc. (although note that
rounding and truncation will still have to be done even in this
case, and there will be cases where precision is lost in ways that
are similar to the ones we've been discussing in this thread)

Perhaps this hypothetical language would convert decimal numbers to
rationals, as follows:

(134.45 * (1.0/0.1))
becomes: ((134 + (45/100)) * (1 / (1/10)))

This could be algebraicly reduced before anything is evaluated:

((134 + (45/100)) * (1 / (1/10)))
=> ((13400 + 45) * 10) / 100
=> (13445 / 10)
=> (2689 / 2)
=> 1344 + 1/2

Of course, how would you algebraicly reduce this statement
if the values of X, Y, and Z aren't known until run time?

(X * (Y/Z))

2. Parentheses around expressions are suggestions only and no longer
specify strict evaluation order.

For example, statement A might be transformed to statement B by the
compiler:

A. (134.45 * (1.0/0.1))
B. ((134.45 * 1.0) / 0.1)

But what would you do in this case?

(X * (Y/Z))

Should the order of evaluation be changed at run time, depending on
the values of X, Y, and Z at the time that the statement is
encountered? If so, what algorithm would you use for deciding when
and how to change the evaluation order?
 
T

trans. (T. Onoma)

On Sunday 31 October 2004 10:31 am, Lloyd Zusman wrote:
|
| It's clear that you agree that we can't use floating point numbers to
| achieve the goal that you mentioned. That's one of the main points of
| the message of mine from which you culled the above quotes.

Sure. Although I never really disagreed. I've merely suggested that I believe
that it may be possible to expand fp to accommodate. Whether you still call
it fp or something else. So I'm not sure why you were making it, just to
clarify my position? Anyway...

| In that same message of mine, I offered two characteristics of a new,
| hypothetical computer language which on the surface might appear to
| provide a solution to the issues that you raise. What comments do you
| have about these characteristics? I will repeat them here:

Okay, I'm not sure how your language helps, but maybe you have a point to
this? If so I'd prefer you'd just say what it is. This sort of smack of
trying to lead me blindly in order drop me over a cliff. But maybe not, and I
could care less if so, so I'll honestly give you my thoughts.

| 1. No floating point arithmetic is done by default; rather, all
| arithmetic involving values with decimal points is done with
| something like Rationals, BigDecimals, etc.

Okay.

| (although note that
| rounding and truncation will still have to be done even in this
| case, and there will be cases where precision is lost in ways that
| are similar to the ones we've been discussing in this thread)

(Right, I do understand that we have limited storage capacity, so obviously we
can't store more information then we have room for. And this does lead to the
necessity of truncing or rounding _informationally abundant_ results. But one
of the things I have argued is that this doesn't apply to a number like 1/3,
it is quite reasonable to store this exactly by simple storing the fact of
repetition.)

| Perhaps this hypothetical language would convert decimal numbers to
| rationals, as follows:
|
| (134.45 * (1.0/0.1))
| becomes: ((134 + (45/100)) * (1 / (1/10)))
|
| This could be algebraicly reduced before anything is evaluated:
|
| ((134 + (45/100)) * (1 / (1/10)))
| => ((13400 + 45) * 10) / 100
| => (13445 / 10)
| => (2689 / 2)
| => 1344 + 1/2
|
| Of course, how would you algebraicly reduce this statement
| if the values of X, Y, and Z aren't known until run time?
|
| (X * (Y/Z))

Okay you want to reduce to separate out the integer part and the fractional
part.

[XY/Z] + {XY/Z}

Assuming X, Y and Z are always integers, maybe you can do some generalized
expansion, but I don't readily see an _algebraic_ solution. I suspect it
might not be possible. Nonetheless without knowing X, Y, and Z at all, all I
think we can really do is create a sort of continution on a computational
solution (AFIKT)

q = fn { |a,b| i = a; while b <= i; i=i-b; c++; end; return c }
r = fn { |a,b| i = a; while b <= i; i=i-b; c++; end; return i }
s = fn { |x,y,z| q(xy,z) + r(xy,z)/z) }

But I'm not sure what you after here. So maybe you can fill me in.

| 2. Parentheses around expressions are suggestions only and no longer
| specify strict evaluation order.
|
| For example, statement A might be transformed to statement B by the
| compiler:
|
| A. (134.45 * (1.0/0.1))
| B. ((134.45 * 1.0) / 0.1)
|
| But what would you do in this case?
|
| (X * (Y/Z))
|
| Should the order of evaluation be changed at run time, depending on
| the values of X, Y, and Z at the time that the statement is
| encountered? If so, what algorithm would you use for deciding when
| and how to change the evaluation order?

A set of identities for moving parentheses around. They seems doable. As long
as they're strict identities.

Okay so now what?


By the way, this looks promising:

http://www.cse.lehigh.edu/~caar/papers/mikes-phd.ps

T.
 
T

trans. (T. Onoma)

| http://www.sunsite.ubc.ca/DigitalMathArchive/Euclid/byrne.html
|
| It looks interesting.

Oh I almost forgot about this! Yes, the Elements rock. Some of the earliest
(and I think THE earliest _complete_) mathematical works we have. The first
Proposition is beautiful too - how to construct an equilateral triangle. I've
thought about getting a tattoo of that. And of course it all culminates in
the construction of the five regular solids.

Without a Euclid, there could have been no Archamides, nor Ptolemy, nor
Kepler, nor Descartes, nor Newton, nor Einstein --or Matz for that matter.

T.
 

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,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top