Hello, Eric,
excellent, although I think, that the textbooks prefer this round:
round: func [n [number!] p [integer!] /local factor r] [
factor: 10 ** (- p)
n: 0.5 * factor + n
n - either negative? r: n // factor [factor + r] [r]
]
; where
>> round -0,5 0
== 0
>
> Hi Michal, Joel,
>
> I've had format.r up on rebol.org for a long time, hoping
someone
> would give me a good idea on how to improve it. Joel's ROUND is
a
> great idea. First, here's a version of ROUND that can handle
values
> where to-integer chokes, fractions less than one, and negative
numbers:
>
> round: func [n [number!] p [integer!] /local factor neg] [
> if negative? n [n: (- n) neg: true]
> factor: 10.0 ** p
> n: n * factor + 0.5
> n: n - (n // 1) / factor
> either neg [- n][n]
> ]
>
> Now I've made a new version of FORMAT, which uses the logic of
ROUND and
> produces a string representation in decimal format, pads with
zeros, etc.
> It also will format all the values in a block in one go. Note
that REBOL
> forms any value less than .1 into exponential notation, you have
to use a
> special formatting function to get it into decimal format. It's
really
> incredible that a language that prides itself on being readable
to humans
> doesn't have a standard way to do this.
>
> >> pi / 100
> == 3.14159265358979E-2
> >> round pi / 100 5
> == 3.142E-2
> >> format pi / 100 5
> == "0.03142"
>
> Note that FORMAT has a refinement /full which won't work without
the
> function FULL-FORM. I've been working on this with Larry
Palmiter and
> Gerald Goertzel. It'll be available on rebol.org in a couple of
days.
> FULL-FORM is meant to give the simplest possible string
representation
> of a decimal value that will load back to exactly the same
value.
>
> >> form pi
> == "3.14159265358979"
> >> pi - load form pi
> == 3.10862446895044E-15 ; not equal!
> >> full-form pi
> == "3.141592653589793"
> >> pi - load full-form pi
> == 0 ; equal!
>
> Have fun,
> Eric
>
> ===========
>
> format: func [
> {CONVERTS Rebol data into formatted strings.}
> item "value or block of values to format - block values are
reduced first"
> decimal [integer! block! unset!]
> {optional decimal places to leave (2 by default)}
> width [integer! block! unset!]
> {optional width of formatted string}
> /full "use extra precision in forming decimal values"
> /local n neg p factor exponent
> ;
> ; Examples:
> ;
> ;>> print format [pi exp 1]
> ;3.14 2.72
> ;>> print format [pi exp 1] 4 ; specifying precision
> ;3.1416 2.7183
> ;>> print format [pi exp 1][4 8] ; using different precisions
> ;3.1416 2.71828183
> ;>> print format [pi exp 1] 4 10 ; pad with spaces
> ; 3.1416 2.7183
> ;>> format pi * 1000 -2 ; round off to nearest
hundred
> ;== "3100"
> ;>> print format pi 16
> ;3.1415926535897900 ; precision given by FORM
> ;>> print format/full pi 16
> ;3.1415926535897930 ; maximum precision
> ;>> print format exp 1 16
> ;2.7182818284590500
> ;>> print format/precise exp 1 16
> ;2.7182818284590452
> ;
> ; Note: DECIMAL must be specified before specifying WIDTH.
Making DECIMAL and
> ; WIDTH optional is for convenience when entered at the prompt.
Both should
> ; be specified within programs.
> ;
> ][
> if not value? 'decimal [ decimal: 2 ] ; supply defaults if
needed
> if not value? 'width [ width: 0 ]
> if object? item [ item: next second item ]
> either any-block? item [
> if integer? decimal [ decimal: reduce [decimal] ]
> if integer? width [ width: reduce [width] ]
> n: to block! reduce item ; won't change values in
lists and hashes
> while [not tail? n][
> either any-block? first n [ ; recurse with all
format values
> change/only n format first n head decimal head
width
> ][ ; use current
format value
> change/only n format first n first decimal first
width
> ]
> n: next n
> ; get next format values, or reuse
the last one
> if 1 < length? decimal [ decimal: next decimal ]
> if 1 < length? width [ width: next width ]
> ]
> ][
> if block? decimal [ decimal: first decimal ]
> if block? width [ width: first width ]
> if not number? decimal [ decimal: 2 ]
> if not number? width [ width: 0 ]
> either number? item [
> if negative? item [item: (- item) neg: true]
> factor: 10 ** decimal
> item: item * factor + 0.5
> item: item - (item // 1)
> n: either full [full-form item][form item]
> if p: find n "." [
> if 2 <> index? p [make error! "FORMAT: funny
decimal point"]
> remove p
> p: remove find n "E"
> exponent: to integer! p
> clear p
> insert/dup tail n "0" exponent + 1 - length? n
> ]
> if positive? decimal [
> insert/dup n "0" 1 + decimal - length? n
> insert skip tail n (- decimal) "."
> ]
> if all [
> negative? decimal
> n <> "0"
> ][insert/dup tail n "0" (- decimal)]
> if neg [insert n "-"]
> ][
> n: form item
> ]
> ; pad with spaces
> either width < 0 [
> insert/dup tail n " " 0 - width - length? n
> ][
> insert/dup n " " width - length? n
> ]
> ]
> head n
> ]
>
>
>