[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.
>
> ; Ladislav Mecir, Gregg Irwin (minor adjustment)
> 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][1]]
> factor: either places [
> 10 ** (negate pl)
> ] [
> either to-interval [interval] [1]
> ]
> ;-- 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
Sponsor:
In questo momento di incertezza il modo sicuro per mandarti in vacanza lo abbiamo trovato
noi
Invitaci, e ti spiegheremo tutto.
Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=271&d=18-2