#### Do you have a question? Post it now! No Registration Necessary. Now with pictures!

## Re: Rounding issue

Makes sense. Its either exact or rounded for display only. Either way,

the internal representation produces the same result as exact, to the

viewer.

Wrong. Percentage calculations are linear, the percentage being the

slope. The result is NOT an integer in a calculator nor computer.

Wrong. I gave you the formulae to display EXACT representation given the

column you want to round to.

Its hard to believe that say the OMB has any problems at all using floating

point numbers where formulae and fractions are everything.

Its also amazing that any computational accuracy takes place at all.

I can categorically tell you that .149999999999999000000000 equals .15

The difference can't be measured, tasted, felt or seen. It only exists

in an 80 bit register so far to the right, its meaningless and won't

affect any other calculation at all !!

my $f3 = .149999999999999000000000;

print getFmtRound($f3,8),"\n";

sub getFmtRound

{

my ($val,$width) = @_;

my $fmt = "%.$width"."f";

return sprintf $fmt,(($val

*** 10***

***($width+1))+.5)/(10****($width+1));

}

Output:

0.15000000

-sln

## Re: Rounding issue

sln@netherlands.com wrote:

) Makes sense. Its either exact or rounded for display only. Either way,

) the internal representation produces the same result as exact, to the

) viewer.

Floating point is rounded during almost any calculation you care

to do with it. That's the whole problem.

) Wrong. Percentage calculations are linear, the percentage being the

) slope. The result is NOT an integer in a calculator nor computer.

Yes they are, as long as you keep track of factors of 10 separately.

That is: <integer> times <n%> is <integer times n> divided by 100.

You just separately (implicitly) keep track of that 'divided by 100' bit.

If you want accuracy to 0.1%, just work with promilles instead, etc.

*)>If you use floating point internally, then the display result will not*

*)>always be exact.*

)

) Wrong. I gave you the formulae to display EXACT representation given the

) column you want to round to.

The floating point number

***itself***will not be exact. It will have

internal rounding errors because it has limited precision.

) Its hard to believe that say the OMB has any problems at all using floating

) point numbers where formulae and fractions are everything.

I find it very easy to believe. Floating point inherently has rounding

errors. You need a lot of careful analysis to make sure that you always

get the correct result. If that is even possible.

Using fractions, you want exact results ? Use rationals. It's that simple.

) my $f3 = .149999999999999000000000;

) <snip>

) 0.15000000

So you're saying that the OP should round twice ?

Once to 8 digits and then to 2 digits ?

Why 8 ? Why not 5, or 10 ?

How do you know that this magic 8 will always give the correct result ?

Answer: you don't. Use an exact representation.

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

## Re: Rounding issue

The latter is misleading. The decimal format is neither necessary nor

sufficient for an exact representation.

Decimal fractions can be represented exactly in base 10

Binary fractions can be represented exactly in base 2.

So,

***if***you need to represent values like 115/100 (which happens to be

common in finance, not even the UK uses shilling and pence any more),

they can be represented exactly in decimal, but not in binary.

But if you need other fractions, decimal won't help you. For example, if

you an American and have decided to store some length measurements in

feet. And now you need to store a length of 1 inch. Well that's 1/12 of

a feet, and there is no way to represent this exactly in a decimal

floating (or fixed) point number. Either you have to round it (and then

it doesn't matter much whether you round to decimal or binary) or you

have to rewrite your program to store everything in inches.

How is a percentage calculation "fixed point"? Financial calculations

are usually fixed point, but a percentage calculation per se isn't.

For example, 19 % of 7.55 is 1.4345, but if that is an amount of money,

it will be rounded to either 1.43 or 1.44.

Integers won't help in general. For example, if 8.99 is 119 %, how much

are 100 %? With rationals, you can represent the result exactly

(899/119), but with an integer, fixed, or floating point representation

you can't (unless you happen to use base 119 which isn't likely).

Of course in finance you don't care about the exact result of the

computation, but about the result rounded to a specific number of digits

(usually 2, sometimes 3 or even 5) and for that a fixed point (or

integer) representation is nice.

hp

## Re: Rounding issue

Then I

___strongly___suggest to brush up on computer numerics. Writing a

financial application that is sound is anything but trivial. So far you

discovered merely the tip of the iceberg of potential issues.

Just one other tiny glimpse into the peculiarities of financial

applications: If you have 5 of those 0.015$ amounts, should their total

be 0.75 or should their total be 1.00?

And there are numerous other pitfalls....

With "as they are" I suppose you mean in the decimal system.

No, Perl does not provide BCD natively (Binary Coded Decimals; someone

else already pointed that out). The reason is simple: they not only take

up more space (probably a minor issue on modern hardware) but more

important most hardware does not support BCD arithmetic, therefore all

calculations would have to be handcoded in software, making them very

slow.

I think you still don't recognize the basic issue: what you are asking

for cannot be done. Not because of a limitation in the binary system,

but because of a fundamantal mathematical limitation: if you have a tax

of 1/3 of one dollar, then how do you suggest to represent that value in

your favoured decimal system. You can not as we all know from 3rd grade

math. Therefore you have to deal with those rounding imperfections, no

matter which system (binary, decimal, ...) you are using. Just saying "I

want to use decimal instead of binary" doesn't absolve you from that

requirement.

How to deal with them is being tought in Computer Numerics, and that's

why I suggest several times already to brush up on that.

And you will still run into the same fundamental limitations.

Well, you got a few pointers to maybe helpful modules. If they don't

suit you needs then you are always free to write your own BCD module.

But as I said, even BCD won't solve your rounding problem, they "bad"

numbers will just be different.

jue

## Re: Rounding issue

Does anyone else find this argument ("We have to use the CPU's floating-point

because anything else is too slow") a bit odd? Did we not once have CPUs with

no floating point at all?[1] It was all "in software", and at about 1MHz too.

Still, somehow, things got done.

I wouldn't be surprised if arbitrary-precision GMP-based Math::BigRat on a

recent machine outperforms the limited-precision software floating-point that

was used in the old days. But still people say "Too slow. Gotta use the FPU

for speed." Really?

Will there ever be a time when our need for speed is satiated, and we can

start thinking about making it easier to get correct results, instead of

bad results quickly? Can a well-rounded, general-purpose language like perl

ever decide that computers are fast enough now, that accuracy-preserving

"bignum" should be the default mode, and FPU speed freaks should be the ones

importing a special module to meet their needs?

If not, then can we at least hope that in the future, Math::BigRat will

play well with sprintf?

[1] I even remember being surprised when I found out the 80x86 could do

integer multiplication in a single instruction. No shift-add-shift-loop

subroutine?! Then I saw "idiv" and was sure someone was joking.

--

Alan Curry

## Re: Rounding issue

pacman@kosh.dhis.org (Alan Curry) wrote:

Please note I said "very slow", I didn't say "too slow". The first is a

comparison against hardware supported arithmetic and can be measured.

The second is an empirical evaluation that has to be made for the

individual application.

Of course, the question is more if you are patient enough to wait that

long considering today's applications. Somehow I have a feeling that

viewing a video or running a graphic intensive game on a 386 wouldn't be

much fun ;-) .

Well, you can always do a benchmark test.

I'm not sure if that's really the issue.

There are only very few areas where a number has to be accurate to the

last digit, finance being the most obvious.

Pretty much any other application area really doesn't care that much

about precision. Typically either the input data itself is only

approximate to begin with. It really doesn't matter if the readout on

that 5$ digital thermometer from the hardware store is 25.34 or 25.35

degree, its accuracy is lower than the display increment anyway.

Or there is no benefit for a result that is accurate to the last digit.

For example it really doesn't matter if it takes 2 hours, 4 minutes,

25.1234 seconds to reach your destination or 2 hours, 4 minutes, 25.1235

seconds, in particular as the distance as well as the speed are both

only rough approximations in the first place.

Same goes for graphics: if the color for a particular pixel is off by

one and the immediate neighbour colour is shown instead your eye would

never notice.

Same goes for parts manufacturing: those machining tolerances are orders

of magnitudes larger then any rounding error.

Same for architecture and building plans, construction, engineering,

surveying, ... you name it. The list goes on and on while I feel hard

pressed to name an area beside finance where the accuracy of the last

digit is really significant.

Remember those slide rulers and tables of logarithms? I still remember

how we learned in school how to use them properly, i.e. when and how to

round and which precision to expect and were warned sternly not to hunt

for false precision. And those rulers and tables were used to

sucessfully build rockets, airplanes, and nuclear bombs.

Today even a simple 16bit binary FPU is way(!) more accurate than those

rulers and tables. I really don't think we need more precision but a

better understanding why hunting for more precision is pointless.

BTW: Last but not least teachers would also show us how to rearrange our

calculations, such that using those tools would introduce the least

error. And that is what's missing in our OP's understanding. A computer

is a tool. You need to understand

___how___to use it and how to arrange

your calculations to not screw up your final result. Famous example:

adding a very long sequence of very small numbers to a very large

number.

As I said: revisit Computer Numerics.

jue

## Re: Rounding issue

However, we are talking about perl here, not machine code. How much of

the time spent executing a perl "multiply" operator is spent

multiplying, and how much is spent manipulating the stack, checking

whether the operands are NVs or UVs or PVs, etc.?

Even if the actual multiplication is 10 or 100 times slower, how much

slower does the "multiply" operator become? And how much slower does the

whole program (which presumably does other things besides multiplying)

become?

[rearranged]

Yes, you would need to do that. It's very hard to guess how much the

effect would be.

Few codecs or 3d engines are written in Perl, AFAIK.

[lots of good examples snipped]

I fully agree.

hp

## Re: Rounding issue

On Tue, 18 Aug 2009 20:04:37 +0200, Marten Lehmann wrote:

Then you need to define first what the correct result is, which is

actually harder then it looks.

I worked on programs that defined results up to 5 digits after the

decimal point and had exact rounding rules for every step in the

calculations. Yes, these were financial programs and no, you will

probably not encounter them unless you work at an insurance company.

The solution used by 99% of programs I know is to use a suitably large

integer type to represent cents, converting to $, E, whatever on output.

M4

## Re: Rounding issue

I fear you stepped not only into a mathematical but at the same

time legal minefield;-)

As others have pointed out there's no "as they are". You are always

dealing with a certain representation of a number. (Finite) rational

numbers can be represented with a limited number of bits in a repre-

sentation that uses a nominator and denominator. But once you want

to write them in a system with a decimal point in whatever base you

choose most numbers can't be represented exactly (and that are just

the rational numbers). Which these few "lucky numbers" are depends

on the base.

Yes. And thus there are, as far as I know (but I am not an expert

on this at all and just have read a bit here an there, so take this

ith a big grain of salt), certain regulations that tell how you have

to do it. That's because there is no "right" and simple way to deal

with these problems, so instead certain rules of how to do it in a

at least in a consistent way where set up. They range from the ques-

tion "should I apply the tax to each item individually and then add

them up or add them up first and then calculate the tax" to "how

many digits after the decimal point have to be taken into account",

how rounding is to be done consistently (which doesn't mean mathe-

matically correct!).

The "most mathematically correct" way to go is use something like

Math::BigRat, hoping that you don't have to deal with operations

that result in irrational numbers (like taking square roots just

to mention a very simple case) - then all bets are off. If you can

reduce everything to basically addition, subtraction, multiplica-

tion and division (which also covers exponentiation with integer

exponents) you should be fine with that. Anything more complica-

ted is likely to get you to end up with irrational numbers.

I fear that most "correctly" written programs in that problem domain

("correctly" in the sense that they satisfy the local regulations)

have to look a bit "ugly", at least in parts. The best way is probably

to write a module that takes care of all the "ugly" stuff, so the main

part of the program doesn't.

In a database you (normally) only store things. So it's easy to e.g.

store the string (or BCD) representation of "0.15" in a database in

this case. The real problems arise when you have to do something

with these numbers (and that holds also for a database when you

have e.g. stored procedures, they also have to do calculations in

some representation). And what do you think is going to be stored

in the database when you ask it to store the value 1.144999999736

(i.e. the result of some floating point computation) in the 10,2

format? It's rather likely going to be "1.14" and not the "1.15"

you might be wishing for.

Since there are no general mathematically correct solutions for

those problems they can't be easily incorporated into a program-

ming language. As far as I know there are regulations that tell

how to do things "correctly - but this definition of what is

"correct" may be different in different countries (or may even

already differ if you are calculating taxes or interest rates -

but as I said, I am no real expert on this).

What you're asking for is a simple solution to an extremely com-

plicated problem. And a general solution, unfortunately, doesn't

(and can't) exist. As someone else pointed out, you have to first

define what the "correct" behaviour actually is. But since what

is "correct" is not well-defined the very best you can hope for

is that someone else came up with the same definition of "correct"

before and published a module that implements this "correct" way.

Otherwise you have to write one yourself.

Regards, Jens

--

\ Jens Thoms Toerring ___ jt@toerring.de

\__________________________ http://toerring.de

## Re: Rounding issue

Print both numbers with 20 digits and note the difference.

For further information please see 'perldoc -q 999' or revisit your

notes on your "Basics of Computer Numerics" class.

jue

PS: you could argue that 1.5 should have been rounded down to 1 because

the 1.5 is exactly 5 with all following digits being 0, but alas, that's

not how it's implemented.

jue

## Re: Rounding issue

As Ben said, the 1,5 is not really 1.5 in floating point terms.

However, this below gets what you want.

If your application is accounting, and your doing discreet

calculations that in PRINT you want them to add up to a correct

"visual" total, then this is what you want.

The reassignment of course is the $newval = sprintf();

You must make sure you are only dealing with fractions of cent

and that it would not be the case of it being used itteratively

in a future calculation.

At least, I wouldn't want my bank to.

-sln

=======================

use strict;

use warnings;

my $f1 = 1.5;

my $f2 = .15;

print sprintf("%.0f", $f1). "\n";

print sprintf("%.1f", $f2). "\n";

print "\n";

print sprintf("%.0f", (($f1 * 100)+5)/100 ). "\n";

print sprintf("%.1f", (($f2 * 100)+5)/100). "\n";

______END

______

Output:

2

0.1

2

0.2

## Re: Rounding issue

On Mon, 17 Aug 2009 16:19:40 -0700, sln@netherlands.com wrote:

^^

I'm sorry these should be ' + .5'

print sprintf("%.0f", (($f1 * 100) + .5)/100 ). "\n";

print sprintf("%.1f", (($f2 * 100) + .5)/100). "\n";

Now $f1,$f2 can be used with a common format string, like "%.1f", or "%.0f"

and be consistant.

-sln

## Re: Rounding issue

On Mon, 17 Aug 2009 16:37:37 -0700, sln@netherlands.com wrote:

It can be generalized.

It only works up to the width of the mantissa.

Which is what 8 digits? So don't set the width to say 40.

A width of 2 max should do fine.

-sln

===============================

use strict;

use warnings;

my $f1 = 1.5;

my $f2 = .15;

my ($n1,$n2) = (

getFmtRound($f1,40),

getFmtRound($f2,40)

);

print "$n1\n$n2\n\n";

print getFmtRound($f1,0),"\n";

print getFmtRound($f2,1),"\n";

sub getFmtRound

{

my ($val,$width) = @_;

my $fmt = "%.$width"."f";

return sprintf $fmt,(($val

*** 10***

***($width))+.5)/(10****($width));

}

______END

______

1.5000000000000000000000000000000000000000

0.1499999999999999900000000000000000000000

2

0.2

#### Site Timeline

- » search for hex characters in a binary file and remove them
- — Next thread in » PERL Discussions

- » log timestamp a script is used
- — Previous thread in » PERL Discussions

- » s suffix question
- — Newest thread in » PERL Discussions

- » Adblock Testscript problem
- — The site's Newest Thread. Posted in » HTML Markup Language