2009-04-11 21:30:51 -04:00
|
|
|
! Copyright (C) 2004, 2009 Slava Pestov.
|
2007-09-20 18:09:08 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2009-04-11 21:30:51 -04:00
|
|
|
USING: kernel math.private namespaces sequences sequences.private
|
2009-05-02 14:45:38 -04:00
|
|
|
strings arrays combinators splitting math assocs byte-arrays make ;
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: math.parser
|
|
|
|
|
|
|
|
: digit> ( ch -- n )
|
2009-10-22 21:28:00 -04:00
|
|
|
127 bitand {
|
|
|
|
{ [ dup CHAR: 9 <= ] [ CHAR: 0 - ] }
|
|
|
|
{ [ dup CHAR: a < ] [ CHAR: A 10 - - ] }
|
|
|
|
[ CHAR: a 10 - - ]
|
|
|
|
} cond
|
|
|
|
dup 0 < [ drop 255 ] [ dup 16 >= [ drop 255 ] when ] if ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-02-06 21:05:03 -05:00
|
|
|
: string>digits ( str -- digits )
|
2009-04-11 21:30:51 -04:00
|
|
|
[ digit> ] B{ } map-as ; inline
|
2008-02-06 21:05:03 -05:00
|
|
|
|
2009-04-11 21:30:51 -04:00
|
|
|
: (digits>integer) ( valid? accum digit radix -- valid? accum )
|
2009-10-22 21:28:00 -04:00
|
|
|
2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if ; inline
|
2009-04-11 21:30:51 -04:00
|
|
|
|
|
|
|
: each-digit ( seq radix quot -- n/f )
|
|
|
|
[ t 0 ] 3dip curry each swap [ drop f ] unless ; inline
|
|
|
|
|
|
|
|
: digits>integer ( seq radix -- n/f )
|
|
|
|
[ (digits>integer) ] each-digit ; inline
|
2008-02-06 22:15:47 -05:00
|
|
|
|
2008-02-06 21:05:03 -05:00
|
|
|
DEFER: base>
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
SYMBOL: radix
|
2008-02-10 02:40:17 -05:00
|
|
|
SYMBOL: negative?
|
|
|
|
|
2009-04-11 21:30:51 -04:00
|
|
|
: string>natural ( seq radix -- n/f )
|
2009-04-13 21:25:55 -04:00
|
|
|
over empty? [ 2drop f ] [
|
2009-10-22 21:28:00 -04:00
|
|
|
[ over CHAR: , eq? [ 2drop ] [ [ digit> ] dip (digits>integer) ] if ] each-digit
|
|
|
|
] if ;
|
2009-04-11 21:30:51 -04:00
|
|
|
|
2008-06-08 16:32:55 -04:00
|
|
|
: sign ( -- str ) negative? get "-" "+" ? ;
|
2008-02-06 21:05:03 -05:00
|
|
|
|
|
|
|
: with-radix ( radix quot -- )
|
|
|
|
radix swap with-variable ; inline
|
|
|
|
|
|
|
|
: (base>) ( str -- n ) radix get base> ;
|
|
|
|
|
|
|
|
: whole-part ( str -- m n )
|
2008-11-23 03:44:56 -05:00
|
|
|
sign split1 [ (base>) ] dip
|
2008-02-06 21:05:03 -05:00
|
|
|
dup [ (base>) ] [ drop 0 swap ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-04-11 21:30:51 -04:00
|
|
|
: string>ratio ( str radix -- a/b )
|
|
|
|
[
|
|
|
|
"-" ?head dup negative? set swap
|
|
|
|
"/" split1 (base>) [ whole-part ] dip
|
|
|
|
3dup and and [ / + swap [ neg ] when ] [ 2drop 2drop f ] if
|
|
|
|
] with-radix ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-04-11 21:30:51 -04:00
|
|
|
: string>integer ( str radix -- n/f )
|
|
|
|
over first-unsafe CHAR: - = [
|
|
|
|
[ rest-slice ] dip string>natural dup [ neg ] when
|
|
|
|
] [
|
|
|
|
string>natural
|
|
|
|
] if ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-09-11 21:11:29 -04:00
|
|
|
: dec>float ( str -- n/f )
|
2009-10-22 19:55:32 -04:00
|
|
|
[ CHAR: , eq? not ] BV{ } filter-as
|
|
|
|
0 over push B{ } like (string>float) ;
|
2009-05-02 14:45:38 -04:00
|
|
|
|
2009-09-11 21:11:29 -04:00
|
|
|
: hex>float-parts ( str -- neg? mantissa-str expt )
|
2009-10-26 18:48:05 -04:00
|
|
|
"-" ?head swap "p" split1 [ 10 base> ] [ 0 ] if* ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
|
|
|
: make-mantissa ( str -- bits )
|
2009-10-26 18:48:05 -04:00
|
|
|
16 base> dup log2 52 swap - shift ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
|
|
|
: combine-hex-float-parts ( neg? mantissa expt -- float )
|
|
|
|
dup 2046 > [ 2drop -1/0. 1/0. ? ] [
|
|
|
|
dup 0 <= [ 1 - shift 0 ] when
|
|
|
|
[ HEX: 8000,0000,0000,0000 0 ? ]
|
|
|
|
[ 52 2^ 1 - bitand ]
|
|
|
|
[ 52 shift ] tri* bitor bitor
|
|
|
|
bits>double
|
2009-10-26 18:48:05 -04:00
|
|
|
] if ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
|
|
|
: hex>float ( str -- n/f )
|
|
|
|
hex>float-parts
|
|
|
|
[ "." split1 [ append make-mantissa ] [ drop 16 base> log2 ] 2bi ]
|
|
|
|
[ + 1023 + ] bi*
|
|
|
|
combine-hex-float-parts ;
|
|
|
|
|
|
|
|
: base>float ( str base -- n/f )
|
|
|
|
{
|
|
|
|
{ 16 [ hex>float ] }
|
2009-09-14 16:03:05 -04:00
|
|
|
[ drop dec>float ]
|
2009-10-22 18:26:22 -04:00
|
|
|
} case ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
2009-09-01 22:14:26 -04:00
|
|
|
: number-char? ( char -- ? )
|
2009-10-22 18:26:22 -04:00
|
|
|
"0123456789ABCDEFabcdef." member? ; inline
|
2009-09-01 22:14:26 -04:00
|
|
|
|
2009-10-22 21:28:00 -04:00
|
|
|
: last-unsafe ( seq -- elt )
|
|
|
|
[ length 1 - ] [ nth-unsafe ] bi ; inline
|
|
|
|
|
2009-09-01 22:14:26 -04:00
|
|
|
: numeric-looking? ( str -- ? )
|
|
|
|
dup empty? [ drop f ] [
|
2009-10-22 21:28:00 -04:00
|
|
|
dup first-unsafe number-char? [
|
|
|
|
last-unsafe number-char?
|
|
|
|
] [
|
|
|
|
dup first-unsafe CHAR: - eq? [
|
|
|
|
dup length 1 eq? [ drop f ] [
|
|
|
|
1 over nth-unsafe number-char? [
|
|
|
|
last-unsafe number-char?
|
|
|
|
] [ drop f ] if
|
|
|
|
] if
|
|
|
|
] [ drop f ] if
|
|
|
|
] if
|
|
|
|
] if ; inline
|
2009-09-01 22:14:26 -04:00
|
|
|
|
2008-02-06 21:05:03 -05:00
|
|
|
PRIVATE>
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-09-11 21:11:29 -04:00
|
|
|
: string>float ( str -- n/f )
|
2009-10-22 18:26:22 -04:00
|
|
|
10 base>float ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: base> ( str radix -- n/f )
|
2009-09-01 22:14:26 -04:00
|
|
|
over numeric-looking? [
|
2009-04-11 21:30:51 -04:00
|
|
|
over [ "/." member? ] find nip {
|
|
|
|
{ CHAR: / [ string>ratio ] }
|
2009-09-11 21:11:29 -04:00
|
|
|
{ CHAR: . [ base>float ] }
|
2009-04-11 21:30:51 -04:00
|
|
|
[ drop string>integer ]
|
|
|
|
} case
|
2009-09-01 22:14:26 -04:00
|
|
|
] [ 2drop f ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-10-22 18:26:22 -04:00
|
|
|
: string>number ( str -- n/f ) 10 base> ; inline
|
|
|
|
: bin> ( str -- n/f ) 2 base> ; inline
|
|
|
|
: oct> ( str -- n/f ) 8 base> ; inline
|
|
|
|
: hex> ( str -- n/f ) 16 base> ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: >digit ( n -- ch )
|
2009-10-22 18:26:22 -04:00
|
|
|
dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] if ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-09-27 18:54:44 -04:00
|
|
|
: positive>base ( num radix -- str )
|
2007-09-20 18:09:08 -04:00
|
|
|
dup 1 <= [ "Invalid radix" throw ] when
|
2009-02-28 16:31:34 -05:00
|
|
|
[ dup 0 > ] swap [ /mod >digit ] curry "" produce-as nip
|
2009-10-28 15:40:15 -04:00
|
|
|
reverse! ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
GENERIC# >base 1 ( n radix -- str )
|
|
|
|
|
2008-02-06 21:05:03 -05:00
|
|
|
<PRIVATE
|
|
|
|
|
2008-09-30 19:28:11 -04:00
|
|
|
: (>base) ( n -- str ) radix get positive>base ;
|
2008-02-06 21:05:03 -05:00
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
M: integer >base
|
2008-09-27 18:54:44 -04:00
|
|
|
over 0 = [
|
|
|
|
2drop "0"
|
|
|
|
] [
|
|
|
|
over 0 > [
|
|
|
|
positive>base
|
2007-09-20 18:09:08 -04:00
|
|
|
] [
|
2008-09-27 18:54:44 -04:00
|
|
|
[ neg ] dip positive>base CHAR: - prefix
|
2007-09-20 18:09:08 -04:00
|
|
|
] if
|
2008-09-27 18:54:44 -04:00
|
|
|
] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: ratio >base
|
|
|
|
[
|
2008-09-27 18:54:44 -04:00
|
|
|
dup 0 < negative? set
|
2008-09-30 19:28:11 -04:00
|
|
|
abs 1 /mod
|
2009-08-11 18:59:40 -04:00
|
|
|
[ [ "" ] [ (>base) sign append ] if-zero ]
|
2008-02-06 21:05:03 -05:00
|
|
|
[
|
2008-09-27 18:54:44 -04:00
|
|
|
[ numerator (>base) ]
|
|
|
|
[ denominator (>base) ] bi
|
2008-12-03 20:12:48 -05:00
|
|
|
"/" glue
|
2008-09-27 18:54:44 -04:00
|
|
|
] bi* append
|
|
|
|
negative? get [ CHAR: - prefix ] when
|
2008-02-06 21:05:03 -05:00
|
|
|
] with-radix ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: fix-float ( str -- newstr )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
[ CHAR: e over member? ]
|
2008-11-23 03:44:56 -05:00
|
|
|
[ "e" split1 [ fix-float "e" ] dip 3append ]
|
2007-09-20 18:09:08 -04:00
|
|
|
} {
|
|
|
|
[ CHAR: . over member? ]
|
|
|
|
[ ]
|
|
|
|
}
|
2008-04-11 13:53:22 -04:00
|
|
|
[ ".0" append ]
|
2007-09-20 18:09:08 -04:00
|
|
|
} cond ;
|
|
|
|
|
2009-09-11 21:11:29 -04:00
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: mantissa-expt-normalize ( mantissa expt -- mantissa' expt' )
|
|
|
|
dup zero?
|
|
|
|
[ over log2 52 swap - [ shift 52 2^ 1 - bitand ] [ 1022 + - ] bi-curry bi* ]
|
|
|
|
[ 1023 - ] if ;
|
|
|
|
|
|
|
|
: mantissa-expt ( float -- mantissa expt )
|
|
|
|
[ 52 2^ 1 - bitand ]
|
|
|
|
[ -0.0 double>bits bitnot bitand -52 shift ] bi
|
|
|
|
mantissa-expt-normalize ;
|
|
|
|
|
|
|
|
: float>hex-sign ( bits -- str )
|
|
|
|
-0.0 double>bits bitand zero? "" "-" ? ;
|
|
|
|
|
|
|
|
: float>hex-value ( mantissa -- str )
|
2009-09-20 17:48:42 -04:00
|
|
|
16 >base 13 CHAR: 0 pad-head [ CHAR: 0 = ] trim-tail
|
|
|
|
[ "0" ] [ ] if-empty "1." prepend ;
|
2009-09-11 21:11:29 -04:00
|
|
|
|
|
|
|
: float>hex-expt ( mantissa -- str )
|
|
|
|
10 >base "p" prepend ;
|
|
|
|
|
|
|
|
: float>hex ( n -- str )
|
|
|
|
double>bits
|
|
|
|
[ float>hex-sign ] [
|
|
|
|
mantissa-expt [ float>hex-value ] [ float>hex-expt ] bi*
|
|
|
|
] bi 3append ;
|
|
|
|
|
|
|
|
: float>decimal ( n -- str )
|
2009-05-02 14:45:38 -04:00
|
|
|
(float>string)
|
|
|
|
[ 0 = ] trim-tail >string
|
|
|
|
fix-float ;
|
|
|
|
|
2009-09-11 21:11:29 -04:00
|
|
|
: float>base ( n base -- str )
|
|
|
|
{
|
|
|
|
{ 16 [ float>hex ] }
|
2009-09-14 16:03:05 -04:00
|
|
|
[ drop float>decimal ]
|
2009-10-22 18:26:22 -04:00
|
|
|
} case ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
|
|
|
: float>string ( n -- str )
|
2009-10-22 18:26:22 -04:00
|
|
|
10 float>base ; inline
|
2009-09-11 21:11:29 -04:00
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
M: float >base
|
2009-09-11 21:11:29 -04:00
|
|
|
{
|
|
|
|
{ [ over fp-nan? ] [ 2drop "0/0." ] }
|
|
|
|
{ [ over 1/0. = ] [ 2drop "1/0." ] }
|
|
|
|
{ [ over -1/0. = ] [ 2drop "-1/0." ] }
|
|
|
|
{ [ over 0.0 fp-bitwise= ] [ 2drop "0.0" ] }
|
|
|
|
{ [ over -0.0 fp-bitwise= ] [ 2drop "-0.0" ] }
|
|
|
|
[ float>base ]
|
2007-09-20 18:09:08 -04:00
|
|
|
} cond ;
|
|
|
|
|
2009-10-22 18:26:22 -04:00
|
|
|
: number>string ( n -- str ) 10 >base ; inline
|
|
|
|
: >bin ( n -- str ) 2 >base ; inline
|
|
|
|
: >oct ( n -- str ) 8 >base ; inline
|
|
|
|
: >hex ( n -- str ) 16 >base ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-10-22 18:26:22 -04:00
|
|
|
: # ( n -- ) number>string % ; inline
|