Mailing List Archive: 49091 messages

## [REBOL] Re: ROUND function (like TRUNC, FLOOR, etc...)

### From: riusa:email:it at: 18-Feb-2002 9:17

```
First of all: thank you for the function!

after this... a curiosity: why Rebol does not implement native round
functions?

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

> << I'm developing a program in my company, and an engineer asked how I
> round the numbers... but... I discovered (I'm still a newbie...) Rebol
> has only TO-INTEGER function to round a number! No FLOOR, no CEIL, no
> TRUNC!
>
> And... how about Banker's algorithm to round numbers? >>
>
> Here's what I came up with, based on some of Ladislav's excellent
work.
> Watch for word-wrap.
>
>     mod: func [
>         {Compute a remainder.}
>         value1 [number! money! time!] {The dividend}
>         value2 [number! money! time!] {The divisor}
>         /euclid {Compute a non-negative remainder such that: a = qb +
r and
> r < b}
>         /local r
>     ] [
>         either euclid [
>             either negative? r: value1 // value2 [r + abs value2] [r]
>             ;-- Alternate implementation
>             ;value1 // value2 + (value2: abs value2) // value2
>         ][
>             value1 // value2
>         ]
>     ]
>
>     ;-- Note: to-interval does mod-like rounding. If the interval you
>     ;         specify is not evenly divisble into your base, the
result
>     ;         may not be what you expect. E.g. round/to-interval 133
30
>     ;         will round to 120, not 130, because 120 is an even
multiple
>     ;         (read interval) of 30.
>     ; Ladislav Mecir, Gregg Irwin
>     round: func [
>         {Rounds numeric value with refinements for what kind of
rounding
>          you want performed, how many decimal places to round to,
etc.}
>         value [number! money! time!] {The value to round}
>         /up         {Round away from 0}
>         /floor      {Round towards the next more negative digit}
>         /ceiling    {Round towards the next more positive digit}
>         /truncate   {Remaining digits are unchanged. (a.k.a. down)}
>         /places     {The number of decimal places to keep}
>             pl [integer!]
>         /to-interval {Round to the nearest multiple of interval}
>             interval [number! money! time!]
>         /local
>             factor
>     ][
>         ;-- places and to-interval are redundant. E.g.:
>         ;       places 2 = to-interval .01
>         ;   to-interval is more flexible so I may dump places.
>         ;-- This sets factor in one line, under 80 chars, but is it
clearer?
>         ;factor: either places [10 ** (- pl)][either to-interval
> [interval]]
>         factor: either places [
>             10 ** (negate pl)
>         ] [
>             either to-interval [interval] 
>         ]
>         ;-- We may set truncate, floor, or ceiling in this 'if block.
>         if not any [up floor ceiling truncate] [
>             ;-- Default rounding is even. Should we take the specified
>             ;   decimal places into account when rounding? We do at
the
>             ;   moment.
>             either (abs value // factor) <> (.5 * factor) [
>                 value: (.5 * factor) + value
>                 return value - mod/euclid value factor
>             ] [
>                 ;-- If we get here, it means we're rounding off
exactly
>                 ;   .5 (at the final decimal position that is).
>                 either even? value [
>                     truncate: true
>                 ] [
>                     either negative? value [floor: true][ceiling:
true]
>                 ]
>             ]
>         ]
>         if up       [either negative? value [floor: true][ceiling:
true]]
>         if truncate [return value - (value // factor)]
>         if floor    [return value - mod/euclid value factor]
>         if ceiling  [return value + mod/euclid (negate value) factor]
>     ]
>
> HTH!
>
> --Gregg
>

--
Prendi GRATIS l'email universale che... risparmia: http://www.email.it/f