260 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			260 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Factor
		
	
	
| ! Copyright (C) 2004, 2009 Slava Pestov.
 | |
| ! See http://factorcode.org/license.txt for BSD license.
 | |
| USING: kernel math.private namespaces sequences sequences.private
 | |
| strings arrays combinators splitting math assocs byte-arrays make ;
 | |
| IN: math.parser
 | |
| 
 | |
| : digit> ( ch -- n )
 | |
|     H{
 | |
|         { CHAR: 0 0 }
 | |
|         { CHAR: 1 1 }
 | |
|         { CHAR: 2 2 }
 | |
|         { CHAR: 3 3 }
 | |
|         { CHAR: 4 4 }
 | |
|         { CHAR: 5 5 }
 | |
|         { CHAR: 6 6 }
 | |
|         { CHAR: 7 7 }
 | |
|         { CHAR: 8 8 }
 | |
|         { CHAR: 9 9 }
 | |
|         { CHAR: A 10 }
 | |
|         { CHAR: B 11 }
 | |
|         { CHAR: C 12 }
 | |
|         { CHAR: D 13 }
 | |
|         { CHAR: E 14 }
 | |
|         { CHAR: F 15 }
 | |
|         { CHAR: a 10 }
 | |
|         { CHAR: b 11 }
 | |
|         { CHAR: c 12 }
 | |
|         { CHAR: d 13 }
 | |
|         { CHAR: e 14 }
 | |
|         { CHAR: f 15 }
 | |
|         { CHAR: , f }
 | |
|     } at* [ drop 255 ] unless ; inline
 | |
| 
 | |
| : string>digits ( str -- digits )
 | |
|     [ digit> ] B{ } map-as ; inline
 | |
| 
 | |
| : (digits>integer) ( valid? accum digit radix -- valid? accum )
 | |
|     over [
 | |
|         2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if
 | |
|     ] [ 2drop ] if ; inline
 | |
| 
 | |
| : 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
 | |
| 
 | |
| DEFER: base>
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| SYMBOL: radix
 | |
| SYMBOL: negative?
 | |
| 
 | |
| : string>natural ( seq radix -- n/f )
 | |
|     over empty? [ 2drop f ] [
 | |
|         [ [ digit> ] dip (digits>integer) ] each-digit
 | |
|     ] if ; inline
 | |
| 
 | |
| : sign ( -- str ) negative? get "-" "+" ? ;
 | |
| 
 | |
| : with-radix ( radix quot -- )
 | |
|     radix swap with-variable ; inline
 | |
| 
 | |
| : (base>) ( str -- n ) radix get base> ;
 | |
| 
 | |
| : whole-part ( str -- m n )
 | |
|     sign split1 [ (base>) ] dip
 | |
|     dup [ (base>) ] [ drop 0 swap ] if ;
 | |
| 
 | |
| : 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 ;
 | |
| 
 | |
| : string>integer ( str radix -- n/f )
 | |
|     over first-unsafe CHAR: - = [
 | |
|         [ rest-slice ] dip string>natural dup [ neg ] when
 | |
|     ] [
 | |
|         string>natural
 | |
|     ] if ; inline
 | |
| 
 | |
| : dec>float ( str -- n/f )
 | |
|     [ CHAR: , eq? not ] BV{ } filter-as
 | |
|     0 over push B{ } like (string>float) ;
 | |
| 
 | |
| : hex>float-parts ( str -- neg? mantissa-str expt )
 | |
|     "-" ?head swap "p" split1 [ 10 base> ] [ 0 ] if* ;
 | |
| 
 | |
| : make-mantissa ( str -- bits )
 | |
|     16 base> dup log2 52 swap - shift ;
 | |
| 
 | |
| : 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 
 | |
|     ] if ;
 | |
| 
 | |
| : 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 ] }
 | |
|         [ drop dec>float ]
 | |
|     } case ; inline
 | |
| 
 | |
| : number-char? ( char -- ? )
 | |
|     "0123456789ABCDEFabcdef." member? ; inline
 | |
| 
 | |
| : numeric-looking? ( str -- ? )
 | |
|     "-" ?head drop
 | |
|     dup empty? [ drop f ] [
 | |
|         dup first number-char? [
 | |
|             last number-char?
 | |
|         ] [ drop f ] if
 | |
|     ] if ;
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : string>float ( str -- n/f )
 | |
|     10 base>float ; inline
 | |
| 
 | |
| : base> ( str radix -- n/f )
 | |
|     over numeric-looking? [
 | |
|         over [ "/." member? ] find nip {
 | |
|             { CHAR: / [ string>ratio ] }
 | |
|             { CHAR: . [ base>float ] }
 | |
|             [ drop string>integer ]
 | |
|         } case
 | |
|     ] [ 2drop f ] if ;
 | |
| 
 | |
| : 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
 | |
| 
 | |
| : >digit ( n -- ch )
 | |
|     dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] if ; inline
 | |
| 
 | |
| : positive>base ( num radix -- str )
 | |
|     dup 1 <= [ "Invalid radix" throw ] when
 | |
|     [ dup 0 > ] swap [ /mod >digit ] curry "" produce-as nip
 | |
|     dup reverse-here ; inline
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| GENERIC# >base 1 ( n radix -- str )
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| : (>base) ( n -- str ) radix get positive>base ;
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| M: integer >base
 | |
|     over 0 = [
 | |
|         2drop "0"
 | |
|     ] [
 | |
|         over 0 > [
 | |
|             positive>base
 | |
|         ] [
 | |
|             [ neg ] dip positive>base CHAR: - prefix
 | |
|         ] if
 | |
|     ] if ;
 | |
| 
 | |
| M: ratio >base
 | |
|     [
 | |
|         dup 0 < negative? set
 | |
|         abs 1 /mod
 | |
|         [ [ "" ] [ (>base) sign append ] if-zero ]
 | |
|         [
 | |
|             [ numerator (>base) ]
 | |
|             [ denominator (>base) ] bi
 | |
|             "/" glue
 | |
|         ] bi* append
 | |
|         negative? get [ CHAR: - prefix ] when
 | |
|     ] with-radix ;
 | |
| 
 | |
| : fix-float ( str -- newstr )
 | |
|     {
 | |
|         {
 | |
|             [ CHAR: e over member? ]
 | |
|             [ "e" split1 [ fix-float "e" ] dip 3append ]
 | |
|         } {
 | |
|             [ CHAR: . over member? ]
 | |
|             [ ]
 | |
|         }
 | |
|         [ ".0" append ]
 | |
|     } cond ;
 | |
| 
 | |
| <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 )
 | |
|     16 >base 13 CHAR: 0 pad-head [ CHAR: 0 = ] trim-tail
 | |
|     [ "0" ] [ ] if-empty "1." prepend ;
 | |
| 
 | |
| : 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 )
 | |
|     (float>string)
 | |
|     [ 0 = ] trim-tail >string
 | |
|     fix-float ;
 | |
| 
 | |
| : float>base ( n base -- str )
 | |
|     {
 | |
|         { 16 [ float>hex ] }
 | |
|         [ drop float>decimal ]
 | |
|     } case ; inline
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : float>string ( n -- str )
 | |
|     10 float>base ; inline
 | |
| 
 | |
| M: float >base
 | |
|     {
 | |
|         { [ 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 ]
 | |
|     } cond ;
 | |
| 
 | |
| : 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
 | |
| 
 | |
| : # ( n -- ) number>string % ; inline
 |