Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why does 22.5 round to 22?

326 views
Skip to first unread message

David M. Fornalsky

unread,
Jul 18, 1998, 3:00:00 AM7/18/98
to
Hi all,

I'm using the Round function, and when it gets a number, like 22.5, it
rounds
down to 22. Shouldn't it round up to 23? If not, is there a Delphi3 function
I missed somewhere that will round up instead of down? TIA.

- Dave

AlanGLLoyd

unread,
Jul 18, 1998, 3:00:00 AM7/18/98
to
In article <6oqrsi$lmf$1...@Nntp1.mcs.net>, "David M. Fornalsky" <cyg...@mcs.com>
writes:

It's "Banker's Rounding" - even 0.5 rounds down, odd 0.5 rounds up.

Alan Lloyd
alang...@aol.com

David M. Fornalsky

unread,
Jul 18, 1998, 3:00:00 AM7/18/98
to
Ahhh, I see. Short of adding extra code to detect whether it's and odd or
even number, is there any way to get it to round up when it's .5, regardless
of whether it's odd or even? TIA.

- Dave

AlanGLLoyd wrote in message
<199807182025...@ladder03.news.aol.com>...

Message has been deleted

AlanGLLoyd

unread,
Jul 19, 1998, 3:00:00 AM7/19/98
to
In article <6or394$m54$1...@Nntp1.mcs.net>, "David M. Fornalsky" <cyg...@mcs.com>
writes:

>Ahhh, I see. Short of adding extra code to detect whether it's and odd or


>even number, is there any way to get it to round up when it's .5, regardless
>of whether it's odd or even? TIA.
>

Format appears to do "straight" rounding - its kludgy, but simple code..

MyRoundInt := StrToInt(Format('%3.0f', [22.5])));

The figure after the % is the maximum number of digits you will have.

Alternativel you could add the resolution of the single or double you are using
- for a single :-

MyRoundInt := Round(22.5 + 0.0000001);


Alan Lloyd
alang...@aol.com

Harry

unread,
Jul 19, 1998, 3:00:00 AM7/19/98
to

Louie R. Orbeta wrote in message <35B141...@technologist.com>...
>David M. Fornalsky wrote:
>Just trunc the real number, which gives the whole number part, and add
>1.


Careful, If the value is a whole number, say 4.0 do not trunc.

Just trying to help

Cheers

Harry

Diana Broz

unread,
Jul 19, 1998, 3:00:00 AM7/19/98
to
I do it this way

NewNumber := Trunc(OldNumber + 0.5)

This way you avoid any checking.

>Ahhh, I see. Short of adding extra code to detect whether it's and odd or
>even number, is there any way to get it to round up when it's .5,
regardless
>of whether it's odd or even? TIA.
>

> - Dave
>
>AlanGLLoyd wrote in message
><199807182025...@ladder03.news.aol.com>...

>>In article <6oqrsi$lmf$1...@Nntp1.mcs.net>, "David M. Fornalsky"
><cyg...@mcs.com>
>>writes:
>>

David M. Fornalsky

unread,
Jul 19, 1998, 3:00:00 AM7/19/98
to
Thanks everyone for the great suggestions!

- Dave
cyg...@mcs.com

Diana Broz wrote in message <6osv0k$q0o$1...@planja.arnes.si>...

Ray Lischner

unread,
Jul 19, 1998, 3:00:00 AM7/19/98
to
On Sat, 18 Jul 1998 16:26:25 -0500, "David M. Fornalsky"
<cyg...@mcs.com> wrote:

>Ahhh, I see. Short of adding extra code to detect whether it's and odd or
>even number, is there any way to get it to round up when it's .5, regardless
>of whether it's odd or even? TIA.

Ceil

--
Ray Lischner (http://www.tempest-sw.com/)
Author of "Hidden Paths of Delphi 3: Experts, Wizards, and the Open Tools API"

Radamanthus Batnag

unread,
Jul 20, 1998, 3:00:00 AM7/20/98
to David M. Fornalsky

David M. Fornalsky wrote:

> Ahhh, I see. Short of adding extra code to detect whether it's and odd or
> even number, is there any way to get it to round up when it's .5, regardless
> of whether it's odd or even? TIA.
>

Use Ceil, declared in the Math unit.
If you want to round down the number, use Floor.


Radamanthus Batnag


JefSummers

unread,
Jul 20, 1998, 3:00:00 AM7/20/98
to
In article <6or394$m54$1...@Nntp1.mcs.net>, "David M. Fornalsky" <cyg...@mcs.com>
writes:

>Ahhh, I see. Short of adding extra code to detect whether it's and odd or


>even number, is there any way to get it to round up when it's .5, regardless
>of whether it's odd or even? TIA.
>

> - Dave
>
>

Add a tiny amount. Needs to be very tiny relative to the precision of your
data so that it would not interfere with other values - for example, if you are
dealing with money (2 decimal points), could add 0.000001 - a tiny fraction of
a cent to take it up over the half cent but not enough to affect values
otherwise.
/js


Martin Harvey

unread,
Jul 20, 1998, 3:00:00 AM7/20/98
to David M. Fornalsky
Yes, it should be easy.

Can't you change the status word in the 8x87 to select the rounding
mode? Most decent numeric co-processors allow this.

I'll have a look thru moy old asm books. It's certainly not more than 3
or 4 assembly instructions, and if win95 saves processor state properly,
then it shouldn't cause any problems in a multitasking environment.

MH.

David M. Fornalsky wrote:
>
> Ahhh, I see. Short of adding extra code to detect whether it's and odd or
> even number, is there any way to get it to round up when it's .5, regardless
> of whether it's odd or even? TIA.
>
> - Dave
>

> AlanGLLoyd wrote in message
> <199807182025...@ladder03.news.aol.com>...

> >In article <6oqrsi$lmf$1...@Nntp1.mcs.net>, "David M. Fornalsky"
> <cyg...@mcs.com>
> >writes:
> >

Martin Harvey

unread,
Jul 20, 1998, 3:00:00 AM7/20/98
to David M. Fornalsky
Okay. I've looked into it.

The 8x87 supports 4 rounding modes corresponding to bits 10 and 11 of
the 8087 control register:

RC

00 Round to nearest
01 Round to negative infinity
10 Round to positive infinity
11 Round to zero

the default seems to be 00 (round to nearest). You want round to
positive infinity. The best way to do it is this:

unit Rounding;

var
CoProControlReg:word;

procedure SetRoundingMode;

var
TempReg:word

asm
fstcw TempReg
push ax
mov ax,TempReg
mov CoProControlReg,ax
{Now set bit 11 and clear bit 10}
or ax,$800 {I think I've got these constants right...}
and ax,$FBFF
{now load new control word}
mov TempReg,ax
pop ax
fldcw TempReg
end;

procedure ResetRoundingMode;
asm
fldcw CoProControlReg
end;


Simple, eh... you don't need to modify any other code, and it's global
thruought your application.

Martin H.

CyberCat

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
On Mon, 20 Jul 1998 23:31:59 +0100, Martin Harvey
<mc...@harvey27.demon.co.uk> wrote:

>Simple, eh... you don't need to modify any other code, and it's global
>thruought your application.

Don't you mean it's global throughout whichever application may be
running at the time? I always try to ensure that my application does
not affect any others running concurrently.

The elegant answer might be to use Int(X+0.5), which always rounds
correctly (when dealing with positive numbers).

paul.ha...@tg.nsw.gov.au

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
With all of this guff about Banker's rounding and 8087 processor assembly
instructions and modes, has anyone actually looked at the delphi on line help?
It states quite clearly, and I quote (well, cut and paste to be precise):

"If X is exactly halfway between two whole numbers, the result is the number
with the greatest absolute magnitude."

So if you are really getting 22.5 to round to 22, then I think this can be
classed as a 'bug', as it clearly does not meet the documented funtionality!

Of course, I could be completely wrong ;-) \

Regards,
Paul Harrington.


In article <35B3C225...@harvey27.demon.co.uk>,


Martin Harvey <mc...@harvey27.demon.co.uk> wrote:
> Yes, it should be easy.
>
> Can't you change the status word in the 8x87 to select the rounding
> mode? Most decent numeric co-processors allow this.
>
> I'll have a look thru moy old asm books. It's certainly not more than 3
> or 4 assembly instructions, and if win95 saves processor state properly,
> then it shouldn't cause any problems in a multitasking environment.
>
> MH.
>

> David M. Fornalsky wrote:
> >
> > Ahhh, I see. Short of adding extra code to detect whether it's and odd or
> > even number, is there any way to get it to round up when it's .5, regardless
> > of whether it's odd or even? TIA.
> >
> > - Dave
> >
> > AlanGLLoyd wrote in message
> > <199807182025...@ladder03.news.aol.com>...
> > >In article <6oqrsi$lmf$1...@Nntp1.mcs.net>, "David M. Fornalsky"
> > <cyg...@mcs.com>
> > >writes:
> > >
> > >>I'm using the Round function, and when it gets a number, like 22.5, it
> > >>rounds
> > >>down to 22. Shouldn't it round up to 23? If not, is there a Delphi3
> > function
> > >>I missed somewhere that will round up instead of down? TIA.
> > >>
> > >
> > >It's "Banker's Rounding" - even 0.5 rounds down, odd 0.5 rounds up.
> > >
> > >Alan Lloyd
> > >alang...@aol.com
>
>

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

AlanGLLoyd

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
In article <35B3C55F...@harvey27.demon.co.uk>, Martin Harvey
<mc...@harvey27.demon.co.uk> writes:

>00 Round to nearest
>01 Round to negative infinity
>10 Round to positive infinity
>11 Round to zero

Martin
Could you explain exactly what the difference between these is for +ve and for
-ve numbers. Thanks

Alan Lloyd
alang...@aol.com

Manfred Müller-Späth

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
CyberCat wrote:

> Don't you mean it's global throughout whichever application may be
> running at the time? I always try to ensure that my application does
> not affect any others running concurrently.

Ehhrrm, well, correct me if im completely wrong, but in a correct
multitasking environment, no register settings will be mixed up between
the applications/tasks running. Ok, we're talking 'bout Windows <g> ...

Manfred

Ray Lischner

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
On Tue, 21 Jul 1998 06:15:16 GMT, paul.ha...@tg.nsw.gov.au wrote:

>With all of this guff about Banker's rounding and 8087 processor assembly
>instructions and modes, has anyone actually looked at the delphi on line help?
>It states quite clearly, and I quote (well, cut and paste to be precise):
>
>"If X is exactly halfway between two whole numbers, the result is the number
>with the greatest absolute magnitude."
>
>So if you are really getting 22.5 to round to 22, then I think this can be
>classed as a 'bug', as it clearly does not meet the documented funtionality!

The documentation is wrong.

Martin Harvey

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to Maur...@bellsouth.net
CyberCat wrote:
> Don't you mean it's global throughout whichever application may be
> running at the time? I always try to ensure that my application does
> not affect any others running concurrently.

No. Any proper task switcher will save all processor state including all
control, status and flags registers.

The only thing you have to be careful about is that the Win95 task
switcher doesn't correctly save the interrupt mask in 16 bit processes.

MH.

Martin Harvey

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to AlanGLLoyd

Okay. Round to nearest is effectively "round to even" AFAIK

-20.5 -> -20
-21.5 -> -22

20.5 ->20
21.5 ->22

Round to negative infinity, ie always round down:

-20.5 -> -21
-21.5 -> -22

20.5 -> 20
21.5 -> 21

Round to positive infinity, ie always round up:

-20.5 -> -20
-21.5 -> -21

20.5 -> 21
21.5 -> 22

Round to Zero, round down if +, round up if -

-20.5 -> -20
-21.5 -> -21

20.5 -> 20
21.5 -> 21

Interestingly enough, there isn't a "round away from zero".

I hope this helps.

MH.

Kevin W. Gale

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to

CyberCat wrote in message <35b3fe0a...@news.mia.bellsouth.net>...

>On Mon, 20 Jul 1998 23:31:59 +0100, Martin Harvey
><mc...@harvey27.demon.co.uk> wrote:
>
>Don't you mean it's global throughout whichever application may be
>running at the time? I always try to ensure that my application does
>not affect any others running concurrently.
>


Your application cannot affect others in this manner. The OS won't allow it.

I ran into the rounding problem and looked into it in some depth.
For Delphi 3 this seems to be the best solution. It changes the
default value Delphi uses to set the control word.

// Set the 8087 Control Word to force floating point numbers to
// be rounded up instead of to the nearest even.
Set8087CW((Default8087CW or $800) and $FBFF);

The 8x87 supports 4 rounding modes corresponding to bits 10 and 11 of
the 8087 control register:

00 Round to nearest even (this is the default)


01 Round to negative infinity

10 Round to positive infinity (This is the one the above code sets)
11 Round to zero


I'm pretty sure this is an undocumented area so it may not work in
other Delphi versions. Also this may have a bad effect on third
party code that expects 22.5 to round to 22.

Kevin Gale

paul.ha...@tg.nsw.gov.au

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to
This sounds like chicken and the egg stuff. You'd think they'd get such a
fundamental documentation error right after three versions! (I wonder what
D4.0 says?) Well then, for what it is worth, here is my contribution to the
myriad of proposed solutions:

function MyRound(Value: Real);
begin
if Value >= 0 then
begin
if Value - Trunc(Value) = 0.5 then
MyRound := Round(Value + 0.000001)
else MyRound := Round(Value);
end
else
begin
if Value - Trunc(Value) = -0.5 then
MyRound := Round(Value - 0.000001)
else MyRound := Round(Value);
end;
end;

How simple is this?


In article <35b5b511....@news.proaxis.com>,

-----== Posted via Deja News, The Leader in Internet Discussion ==-----

Graham

unread,
Jul 21, 1998, 3:00:00 AM7/21/98
to

CyberCat wrote in message <35b3fe0a...@news.mia.bellsouth.net>...
>On Mon, 20 Jul 1998 23:31:59 +0100, Martin Harvey
><mc...@harvey27.demon.co.uk> wrote:
>
>>Simple, eh... you don't need to modify any other code, and it's global
>>thruought your application.
>
>Don't you mean it's global throughout whichever application may be
>running at the time? I always try to ensure that my application does
>not affect any others running concurrently.
>
>The elegant answer might be to use Int(X+0.5), which always rounds
>correctly (when dealing with positive numbers).
>


My Tupenn'orth on this:

Modifying the 8x87 register. I think this is potentially very dangerous
territory since you don't have private & exclusive use of that resource
and any other program (or even your own through the use of some other
math function ) can easily change it back or to something else.
The only way to use it with ANY form of certainty is to write the
register
value just before you use it - but another app (or thread) could STILL
get
in and change it.

The Cat's (& others') Int(X+0.5) is the way to go. I have seen
suggestions about adding 0.000000xxx1 to the value to 'flip' it to the
right
side, but these posters haven't thought the process out.
When they do the above is actually perfect. Been there - Done that.
Will use it again.
--

Graham W

WIMBORNE Dorset UK

Martin Harvey

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to Kevin W. Gale
Kevin,

Thanks for noting that Delphi provides a function to set the 8087CW. As
a general note to other readers, it's probably better to use the Delphi
function than my assembler (despite the fact that they're probably
identical :-))

MH.

Kevin W. Gale wrote:
>
> I ran into the rounding problem and looked into it in some depth.
> For Delphi 3 this seems to be the best solution. It changes the
> default value Delphi uses to set the control word.
>
> // Set the 8087 Control Word to force floating point numbers to
> // be rounded up instead of to the nearest even.
> Set8087CW((Default8087CW or $800) and $FBFF);
>
>

> Kevin Gale

Martin Harvey

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to Graham
Graham wrote:
> Modifying the 8x87 register. I think this is potentially very dangerous
> territory since you don't have private & exclusive use of that resource
> and any other program (or even your own through the use of some other
> math function ) can easily change it back or to something else.

No.

The whole point of a multitasking OS is that it presents a "virtual
processor" to all processes. All processor state must be saved and
restored between process switches. if this were not the case, one could
not have multitasking operating systems at all, since the argument that
applies to the 8087CW register could also be applied to (for example)
the 8087SW ... but if one didn't save the SW .. then one might apply the
same argument to say that EFLAGS shouldn't be saved ...

In order to produce consistent behaviour, *all* multithreaded task
switchers must save *all* processor state ie:

GP Registers, Segment regs, flags, co pro "cyclic" stack regs, and co
pro control, & status regs.

> The only way to use it with ANY form of certainty is to write the
> register
> value just before you use it - but another app (or thread) could STILL
> get
> in and change it.

Again... no other process can. One of your own threads might.

The only case where the processor is not fully virtualised is when you
are setting or modifying the masks in the programmable interrupt
controller.



> When they do the above is actually perfect. Been there - Done that.
> Will use it again.

Hmm... a bit kludgy for my taste.

MH.

Rune Moberg

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to
paul.ha...@tg.nsw.gov.au wrote:
> This sounds like chicken and the egg stuff. You'd think they'd get such a
> fundamental documentation error right after three versions! (I wonder what
> D4.0 says?) Well then, for what it is worth, here is my contribution


FYI, D4 help file says:
"Round returns an Int64 value that is the value of X rounded to the
nearest whole number. If X is exactly halfway between two whole numbers,
the result is always the even number."


--
Rune

Rune Moberg

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to
Graham wrote:
> Modifying the 8x87 register. I think this is potentially very dangerous
> territory since you don't have private & exclusive use of that resource
> and any other program (or even your own through the use of some other
> math function ) can easily change it back or to something else.

Do you know this for a fact?

The context switching code in the OS (actually doesn't the 386 CPUs and
newer handle much of the hard work themselves?) has to atleast preserve
the CPU registers, the math co-processor's stack plus a variety of flags
and other stuff, and you feel they drew the line when it came to the
80x87's control register? Somehow I doubt that.

> The only way to use it with ANY form of certainty is to write the
> register

Let the OS handle this. Otherwise you'll be stuck preserving everything
you can get your hands on and the OS won't be able to let other
applications run at all... ;-)

--
Rune

Lasse Vågsæther Karlsen

unread,
Jul 22, 1998, 3:00:00 AM7/22/98
to
The normal solution, which has been known since real number rounding was
first invented is the following solution:

I := Trunc(R+0.5);

Harry wrote:

--
Lasse Vågsæther Karlsen
lasse....@stavanger.online.no
http://home.sol.no/~lassevk/

Rune Moberg

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to
Martin Harvey wrote:
> The only case where the processor is not fully virtualised is when you
> are setting or modifying the masks in the programmable interrupt
> controller.

...under Win9X that is.

(you can play around with the PIC freely under NT without affecting
other processes)

--
Rune

Martin Harvey

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to r...@qsd.no
Rune Moberg wrote:
>
> Martin Harvey wrote:
> > The only case where the processor is not fully virtualised is when you
> > are setting or modifying the masks in the programmable interrupt
> > controller.
>
> ...under Win9X that is.

Yep.



> (you can play around with the PIC freely under NT without affecting
> other processes)
>

Oh really? Nice :-)

The way I discovered this little, er "deficiency" of Win9X, was by
developing a multithreaded DOS program with it's own scheduler. It
worked great in DOS only ... but was completely broken when running in a
DOS box.

MH.

0 new messages