The following has been taken from the DAW newsgroup, User Contributed Oct 6 2000
MARF - A Mutually Agreed Rounding Function?!
Aside from UI issues, OS and hardware problems, perhaps one of the most frequently recurring themes in both the old DAC CompuServe Forum, and now here, has been 'How to perform proper rounding of numeric values'.
Interestingly, each time the topic reappears as a new thread, nobody ever refers the questioner back to the previous threads on the subject. It is always a great opportunity to air one's own (usually strictly limited) solution to the problem!
Well, I propose that we use this message thread to, if possible, finally agree upon a proper specification and solution to this problem ... the one that DAC forgot to supply us ... and finally lay this ghost to rest!
So let me kick-off.
Here is what I expect of a proper Rounding function:-
(a) It should be able to cope with all numbers in the DataFlex numeric range ie. ± 99,999,999,999,999.99999999.
(b) Rounding up should occur when the digit to the right of the rounding position is 5 or above, otherwise rounding down should occur. I take this to be a reasonably 'international' convention.
(c) It should be possible to round to any degree of precision. In other words, it should be capable of rounding to any position to the left of the decimal delimiter as well as to the right of it. This, after all, is a frequent requirement in financial reporting. So, for example, if I wish to round to the nearest thousand, then a value of 72637.54 should be returned as 73000.
I have attached a file named ROUNDNUM.FNC which contains a global function that attempts to meet these requirements. Use of the function, named ROUND_NUMBER, is fully documented therein.
My approach is substantially based on some code originally presented by Hendrick van Niekerk in a CompuServe message in October 1997. I note that he has repeated the code in a message reply in the VDF NG on 11-Jun-2000.
I prefer Hendrick's method to all the others I have yet seen. His code is actually contained in a macro command named ROUND THEN. Basically all I have done is to convert his macro into a global function and then extended the scope of the code to provide for rounding to a more flexible degree of precision.
So ... well ... thanks Hendrick!
// =========================================================================== // // The ROUND_NUMBER global function has been designed to return the rounded // value of a given 'numeric' argument at a specified rounding precision. // // The function requires two arguments, as follows:- // // (a) The numeric value to be rounded, where the range of valid values is // +/- 99,999,999,999,999.99999999. // // (b) The rounding precision required. This must be an integer value in the // range -13 to +8. If a value outside this range is used, the nearest // threshold value is substituted. // // Values in the range +1 to +7 perform rounding on the decimal part of // the number. A value of +8 will perform no rounding at all. A zero // value will round to the nearest whole number. Values -1 to -13 will // round progressively to the left of the decimal point (a frequent // requirement in financial reporting). // // If the result of the rounding produces a value outside the valid numeric // range (+/- 99,999,999,999,999.99999999) then a zero value is returned. // // Assumptions:- The only assumptions made have been that the range of // numeric values and the limit of eight decimal places are unlikely to change // in the forseeable future. // // Examples:- // // 1st Argument 2nd Argument Return Value // ------------ ------------ ------------ // 123456.87654321 8 123456.87654321 // 123456.87654321 2 123456.88 // -123456.87654321 2 -123456.88 // 123456.98765432 0 123457 // -123456.98765432 -1 -123460 // 123456.98765432 -2 123500 // 123456.98765432 -3 123000 // 987654 -4 990000 // 987654 -5 1000000 // 987654 -6 1000000 // 987654 -7 0 // // =========================================================================== Function Round_Number GLOBAL number nVal integer iRnd returns Number // If the rounding precision falls in the range -5 to +8, then return:- If (iRnd >= -5) Function_Return ; (Number(Abs(nVal) / nVal) * 0.5 / (Number(10 ^ (iRnd min 8))) + nVal ; / (Number(10 ^ (8 - (iRnd min 8)))) * (Number(10 ^ (8 - (iRnd min 8))))) // Else, where the rounding precision is in the range -6 to -13, return:- Function_Return ; (Number(Abs(nVal) / nVal) * 0.5 * (Number(10 ^ (Abs(iRnd) min 13))) ; + nVal / (Number(10 ^ 13)) / (Number(10 ^ ((Abs(iRnd) - 5) min 8))) ; * (Number(10 ^ 13)) * (Number(10 ^ ((Abs(iRnd) - 5) min 8)))) End_Function