Limiting Precision of Decimals,
[1/9] from: louisaturk::coxinet::net at: 23-May-2002 21:23
Hi rebols,
Is there any way to avoid scientific notation on decimals? For example, I
don't want the E-2 at the end of the following number my program has
calculated:
6.59262575231111E-2
I want instead:
.06592625 <====<<< I would like less precision also.
Louis
[2/9] from: greggirwin:mindspring at: 24-May-2002 16:58
Hi Louis,
<< Is there any way to avoid scientific notation on decimals? For example,
I
don't want the E-2 at the end of the following number my program has
calculated: >>
Here's a rounding function that might do what you want.
; 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]
]
--Gregg
[3/9] from: louisaturk:eudoramail at: 24-May-2002 20:42
Hi Gregg,
Thanks! But I haven't been able to figure out how to use it. Would you
please give me a sample usage?
Louis
At 04:58 PM 5/24/2002 -0600, you wrote:
[4/9] from: greggirwin:mindspring at: 24-May-2002 21:37
Hi Louis,
<< Thanks! But I haven't been able to figure out how to use it. Would you
please give me a sample usage? >>
DOH! I was going to post a simple reply, but it appears you've outsmarted
me. :) If there's only a decimal component, and the value is <~.1, REBOL
returns it with scientific notation. E.g.
>> round/places/truncate 1.0659262575231111 8
== 1.06592625
>> round/places/truncate .0659262575231111 8
== 6.592625E-2
I'll have to think about this. I'm not sure that I want to scale things
internally to work around this issue. Obviously, it should work for all
extremes so that's what we'll have to test for in a redesign. Guess it won't
work for you right now though. Sorry about that. But, thanks for finding the
bug! :)
Anyone else listening in? Any thoughts?
--Gregg
[5/9] from: rpgwriter:yah:oo at: 25-May-2002 0:10
--- Gregg Irwin <[greggirwin--mindspring--com]> wrote:
> Hi Louis,
> << Thanks! But I haven't been able to figure out
<<quoted lines omitted: 19>>
> bug! :)
> Anyone else listening in? Any thoughts?
There's not a bug in your rounding function. As you
note, its just a "feature" of the way REBOL converts
decimal! values to string! values. There is probably a
place for a nice robust function for converting
arbitrary values of any type to strings with all kinds
of formatting options (sort of an sprintf() for
REBOL), but the direct solution to printing decimals
to avoid scientific notation for small values is:
print-val: either greater? value 0.1 [ to-string value
] [ insert remove to-string 1 + value "0" ]
This still has the switch over to scientific notation
at values of >= 1E+15. To totally avoid scientific
notation, this seems to work (written as a function):
dec-to-string: func [ value ] [
z: value
w: ""
for y to-integer log-10 z 0 -1 [
append w to-string to-integer z / power 10 y
z: remainder z power 10 y
]
append w remove to-string 1 + remainder z 1
return w
]
Chris Dicely
[6/9] from: g:santilli:tiscalinet:it at: 25-May-2002 12:32
Hi Gregg,
On Saturday, May 25, 2002, 5:37:55 AM, you wrote:
(CC to Gregg and Luis to avoid list slowness)
GI> Anyone else listening in? Any thoughts?
Sorry for using a nonstandard style... You should be easily able
to fix it for negative numbers (I didn't need them :) and to use
different decimal separators (this is for the italian way).
form-decimal:
func
[ num [number!]
cifre [integer!]
/local str poscifre
]
[ ; ***WARNING*** positive numbers only.
num: abs num
str: make string! 16
either zero? num
[ insert str #"0"
if cifre > 0
[ insert/dup
insert
tail str
#","
#"0"
cifre
] ]
[ if 14 < add cifre log-10 num
[ return form num]
num: form
add
multiply
power 10 cifre
to-decimal num
0,5
clear any [find num "." ""]
poscifre: skip tail num negate cifre
insert/part str num
num: skip num
1 + remainder
subtract
index? poscifre
2
3
while [(index? poscifre) > (index? num)]
[ insert/part
insert
tail str
#"'"
num
num: skip num 3
]
if empty? str [insert str #"0"]
if not tail? poscifre
[ insert
insert/dup
insert
tail str
#","
#"0"
cifre - length? poscifre
poscifre
]
]
str
]
>> form-decimal 1 2
== "1,00"
>> form-decimal 1000 2
== "1'000,00"
>> form-decimal 0.1 2
== "0,10"
>> form-decimal 0.01 2
== "0,01"
>> form-decimal 0.01 5
== "0,01000"
>> form-decimal 0.00001 5
== "0,00001"
>> d: .0659262575231111
== 6.59262575231111E-2
>> form-decimal d 5
== "0,06593"
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[7/9] from: rotenca:telvia:it at: 25-May-2002 13:02
Hi Louis and Gregg
> Anyone else listening in? Any thoughts?
Look at Eric Long's http://www.rebol.org/utility/format.r
---
Ciao
Romano
[8/9] from: greggirwin:mindspring at: 25-May-2002 12:53
Thanks Chris, Gabriele, and Romano!
Louis, it looks like you have a few options to pursue here. I'll be looking
into them as well but let me know if, other than formatting, the ROUND
function misbehaves.
--Gregg
[9/9] from: louisaturk:eudoramail at: 27-May-2002 20:18
Gregg, Chris, Gabriele, and Romano,
Thanks for all the help. I'm still studying your code. I get back with
you ASAP (I still have a lot to learn).
Louis
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted