Qbasicnews.com

Full Version: ROUNDING NUMBERS: Which method do you use? SEE MANY METHODS
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4
In the last couple of days in the challenge regarding "useful programs", Oracle posted the following function to perform rounding to the nearest whole number:
Code:
DEF FNround# (m#) = SGN(m#) * INT(ABS(m#) + .5)
(I took the liberty of streamlining it for the general case.)

I recognized immediately that this was the most precise rounding logic that I had ever seen, because usng the ABS it rounds correctly without being burdened by the sign of the input number. Then, it restores the sign by using the SGN.

After testing Oracle's logic thoroughly, I realized that for at least the last 5 years, I have been rounding negative numbers incorrectly. :oops:

BTW: Ak00ma came up with the following enhancement of Oracle's logic, which handles numbers with implied decimal places:
Code:
DEF FNround# (m#, dec%) = SGN(m#) * INT(10^dec% * ABS(m#) + .5) / 10 ^ dec%

Without much ado, I'll list 3 erroneous rounding methods:
1) Using the CINT. This looks very simple when your numbers to be rounded are in the range of integer values. However, if you round .5 or -.5 you get zero for both. Who knows why, and what other inputs will also fail?

2) Testing the sign and rounding by +.5 or -.5 accordingly. This was my method, but testing shows that it doesn't always work for all negative inputs. The root of the problem is stated in the QB manual: "The INT returns the largest interger less than or equal to to the input¨. Less than/equal does not work the same for positive and negative numbers. Another Basic weirdness.

3) The cavalier method. Just do: INT(NUMB+.5) and hope for the best. Works great for positive numbers, but suffers from obvious problems on negative numbers, compounded by the above less than/equal weirdness.

SUMMARY: Don't take my word for it, do your own testing. You will certainly come to realize that Oracle's approach is the only correct way to round.
BTW: Tested the INT on a negative number in Visual Basic, and got the same error. INT(-123.4) gave -124. :rotfl:
*****
_________________
Code:
RoundedInteger% = UnroundedSingle!
Works most of the time for me, but it has obvious limits.
PROGGER:
You're right, it works *most* of the time, and even handles negative numbers. I just tested it and it has the same problem as a CINT; that is, an input of .5 or -.5 returns a zero. It probably uses the same internal "Convert to INTeger" logic.

BTW: Many years ago I had all kinds of problems with CINT. I don't recall what the other problems were, other than the .5 bug, but I decided back then NEVER to use the CINT again.

I don't know what other "obvious limits " you're referring to.
*****
Don't know what the obvious limits are!?!?!?!?
You try this:

Code:
RoundedInteger% = UnroundedSingle!
When UnroundedSingle! is a very big or very small negative number, like >32767 and <-32768.
Quote:Don't know what the obvious limits are!?!?!?!?
You try this:

Code:
RoundedInteger% = UnroundedSingle!
When UnroundedSingle! is a very big or very small negative number, like >32767 and <-32768.
^
|
|
What he said Smile
You guys are right. Trying to stuff a number outside of an integer range into an integer variable --- this is pretty obvious. Just like an old saying: "You can't get 10 pounds of sh*t into a 5 pound bag".
*****
I'm in vacation, don't expect me to follow this thread...

MS says in its Knowledge base that INT(.5) giving a result of 0 is not a bug, it's just the correct result according to IEEE standard...
Edited: Sorry, wrong quote...


Code:
DOCUMENT:Q23389  21-FEB-1991  [B_QUICKBAS]
TITLE   :Unexpected Result from CINT(.5) in QB87; IEEE Rounds to Even
PRODUCT :Microsoft QuickBASIC Compiler
PROD/VER:3.00
OPER/SYS:MS-DOS
KEYWORDS:B_BasicCom

Summary:

The coprocessor version of QuickBASIC version 3.00 (QB87.EXE) returns
0 (zero) in the following example (as do QuickBASIC versions 4.00,
4.00b, and 4.50; Microsoft BASIC Compiler versions 6.00 and 6.00b; and
Microsoft BASIC Professional Development System (PDS) versions 7.00
and 7.10, which all use the IEEE floating-point format):

   PRINT CINT(1/2)
   PRINT CINT(.5)
   PRINT CINT(1.0/2.0)

Three zeros (0) are printed. This differs from the non-coprocessor
version of QuickBASIC version 3.00 (QB.EXE) and earlier versions,
which instead prints three ones (1).

Compare this with the fact that PRINT CINT(1.5) returns 2 in both the
coprocessor and non-coprocessor versions of QuickBASIC version 3.00
(and in the other more recent products listed above).

The observed rounding difference in the first case above is not caused
by any bug. The IEEE standard dictates that rounding of x.5 occurs to
the even integer nearest to x, for example, CINT(.5)=0, CINT(1.5)=2,
CINT(2.5)=2, CINT(3.5)=4, CINT(4.5)=4, etc.

The non-coprocessor version of QuickBASIC 3.00 (QB.EXE) supports a
different floating-point format, the Microsoft Binary format (MBF),
which rounds differently than the IEEE standard.

End of edit

Second edit: I erased the wrong quote because it was about QB for MacIntosh :o But it said an interesting thing :
Code:
The purpose of this behavior is to prevent an average upward (or
downward) bias as various calculations are rounded. If the number was
always rounded up, there would be an upward bias in calculations.
Rounding to the nearest even number averages out; therefore, no
rounding bias occurs.

End of second edit
Or we could just use the common maths standard, round >=.5 up and <.5 down.

Anyone up for making a swedish rounding function?
INT(number + .5) seems to be mathematically correct. At ±???.5 is always rounds up (toward positive infinity). In those cases, your formula always rounds away from zero. It just depends what you want.
ANTONI,
Very interesting and informative. However, no matter how much authority the IEEE has, these rounding principles are not a global industry standard, and would never be accepted by any CPA or accountant. In accounting practices, if you round 2.5 you should get 3 not 2.

However, in analysing the attached document that you provided, this IEEE rounding phenomenon only occurs in QB when using the CINT function or when assigning a value to a integer variable.

If you use the "normal" way of rounding, which is to add .5 to the positive floating point number and then take the INT of the result, then the above IEEE standard has no effect at all. That is, the values will always be rounded up.

On the other hand, if your program is working and rounding values that are to be used in an IEEE related application, then you should consider emulating the IEEE standard of rounding.

PS: Have a nice vacation, Antoni. Thanks for thinking of us. :wink:
*****
Pages: 1 2 3 4