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
> ]
>
>
>

Reply via email to