1 ! Copyright (C) 2004, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel math.private namespaces sequences sequences.private
4 strings arrays combinators splitting math assocs byte-arrays make ;
32 } at* [ drop 255 ] unless ; inline
34 : string>digits ( str -- digits )
35 [ digit> ] B{ } map-as ; inline
37 : (digits>integer) ( valid? accum digit radix -- valid? accum )
39 2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if
40 ] [ 2drop ] if ; inline
42 : each-digit ( seq radix quot -- n/f )
43 [ t 0 ] 3dip curry each swap [ drop f ] unless ; inline
45 : digits>integer ( seq radix -- n/f )
46 [ (digits>integer) ] each-digit ; inline
55 : string>natural ( seq radix -- n/f )
56 over empty? [ 2drop f ] [
57 [ [ digit> ] dip (digits>integer) ] each-digit
60 : sign ( -- str ) negative? get "-" "+" ? ;
62 : with-radix ( radix quot -- )
63 radix swap with-variable ; inline
65 : (base>) ( str -- n ) radix get base> ;
67 : whole-part ( str -- m n )
68 sign split1 [ (base>) ] dip
69 dup [ (base>) ] [ drop 0 swap ] if ;
71 : string>ratio ( str radix -- a/b )
73 "-" ?head dup negative? set swap
74 "/" split1 (base>) [ whole-part ] dip
75 3dup and and [ / + swap [ neg ] when ] [ 2drop 2drop f ] if
78 : string>integer ( str radix -- n/f )
79 over first-unsafe CHAR: - = [
80 [ rest-slice ] dip string>natural dup [ neg ] when
85 : dec>float ( str -- n/f )
86 [ CHAR: , eq? not ] filter
87 >byte-array 0 suffix (string>float) ;
89 : hex>float-parts ( str -- neg? mantissa-str expt )
90 "-" ?head swap "p" split1 [ 10 base> ] [ 0 ] if* ;
92 : make-mantissa ( str -- bits )
93 16 base> dup log2 52 swap - shift ;
95 : combine-hex-float-parts ( neg? mantissa expt -- float )
96 dup 2046 > [ 2drop -1/0. 1/0. ? ] [
97 dup 0 <= [ 1 - shift 0 ] when
98 [ HEX: 8000,0000,0000,0000 0 ? ]
100 [ 52 shift ] tri* bitor bitor
104 : hex>float ( str -- n/f )
106 [ "." split1 [ append make-mantissa ] [ drop 16 base> log2 ] 2bi ]
108 combine-hex-float-parts ;
110 : base>float ( str base -- n/f )
114 [ "Floats can only be converted from strings in base 10 or 16" throw ]
117 : number-char? ( char -- ? )
118 "0123456789ABCDEFabcdef." member? ;
120 : numeric-looking? ( str -- ? )
122 dup empty? [ drop f ] [
123 dup first number-char? [
130 : string>float ( str -- n/f )
133 : base> ( str radix -- n/f )
134 over numeric-looking? [
135 over [ "/." member? ] find nip {
136 { CHAR: / [ string>ratio ] }
137 { CHAR: . [ base>float ] }
138 [ drop string>integer ]
142 : string>number ( str -- n/f ) 10 base> ;
143 : bin> ( str -- n/f ) 2 base> ;
144 : oct> ( str -- n/f ) 8 base> ;
145 : hex> ( str -- n/f ) 16 base> ;
148 dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] if ;
150 : positive>base ( num radix -- str )
151 dup 1 <= [ "Invalid radix" throw ] when
152 [ dup 0 > ] swap [ /mod >digit ] curry "" produce-as nip
153 dup reverse-here ; inline
157 GENERIC# >base 1 ( n radix -- str )
161 : (>base) ( n -- str ) radix get positive>base ;
172 [ neg ] dip positive>base CHAR: - prefix
178 dup 0 < negative? set
180 [ [ "" ] [ (>base) sign append ] if-zero ]
182 [ numerator (>base) ]
183 [ denominator (>base) ] bi
186 negative? get [ CHAR: - prefix ] when
189 : fix-float ( str -- newstr )
192 [ CHAR: e over member? ]
193 [ "e" split1 [ fix-float "e" ] dip 3append ]
195 [ CHAR: . over member? ]
203 : mantissa-expt-normalize ( mantissa expt -- mantissa' expt' )
205 [ over log2 52 swap - [ shift 52 2^ 1 - bitand ] [ 1022 + - ] bi-curry bi* ]
208 : mantissa-expt ( float -- mantissa expt )
210 [ -0.0 double>bits bitnot bitand -52 shift ] bi
211 mantissa-expt-normalize ;
213 : float>hex-sign ( bits -- str )
214 -0.0 double>bits bitand zero? "" "-" ? ;
216 : float>hex-value ( mantissa -- str )
217 16 >base [ CHAR: 0 = ] trim-tail [ "0" ] [ ] if-empty "1." prepend ;
219 : float>hex-expt ( mantissa -- str )
220 10 >base "p" prepend ;
222 : float>hex ( n -- str )
225 mantissa-expt [ float>hex-value ] [ float>hex-expt ] bi*
228 : float>decimal ( n -- str )
230 [ 0 = ] trim-tail >string
233 : float>base ( n base -- str )
235 { 10 [ float>decimal ] }
237 [ "Floats can only be converted to strings in base 10 or 16" throw ]
242 : float>string ( n -- str )
247 { [ over fp-nan? ] [ 2drop "0/0." ] }
248 { [ over 1/0. = ] [ 2drop "1/0." ] }
249 { [ over -1/0. = ] [ 2drop "-1/0." ] }
250 { [ over 0.0 fp-bitwise= ] [ 2drop "0.0" ] }
251 { [ over -0.0 fp-bitwise= ] [ 2drop "-0.0" ] }
255 : number>string ( n -- str ) 10 >base ;
256 : >bin ( n -- str ) 2 >base ;
257 : >oct ( n -- str ) 8 >base ;
258 : >hex ( n -- str ) 16 >base ;
260 : # ( n -- ) number>string % ;