1 ! Copyright (C) 2018 Alexander Ilin.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: formatting kernel locals math math.bitwise math.functions
4 math.order ryu.data sequences shuffle strings vectors ;
10 : mul-shift ( x mul shift -- y )
11 [ first2 rot [ * ] keep swapd * -64 shift + ] [ 64 - neg ] bi* shift ;
13 : mul-shift-all ( mmShift m mul shift -- vm vp vr )
15 [ [ 1 - swap - ] 2dip mul-shift ]
16 [ [ 2 + ] 2dip mul-shift ]
19 :: pow-5-factor ( x -- y )
21 f 0 [ 2dup x <= swap not and ] [
22 value 5 /mod zero? [ value! 1 + ] [ nipd swap ] if
25 : multiple-of-power-of-5 ( p value -- ? )
28 : double-pow-5-bits ( n -- m )
30 DOUBLE_LOG2_5_NUMERATOR * DOUBLE_LOG2_5_DENOMINATOR + 1 -
31 DOUBLE_LOG2_5_DENOMINATOR /i
34 : decimal-length ( m -- n )
54 } [ dupd >= ] find-last [ 2 + ] [ drop 1 ] if nip ; inline
56 CONSTANT: mantissaBits 52
57 CONSTANT: exponentBits 11
58 CONSTANT: offset 1023 ! (1 << (exponentBits - 1)) - 1
60 :: unpack-bits ( value -- e2 m2 acceptBounds ieeeExponent<=1? neg? string/f )
62 dup mantissaBits exponentBits + bit? :> sign
63 dup mantissaBits bits :> ieeeMantissa
64 mantissaBits neg shift exponentBits bits :> ieeeExponent
67 exponentBits on-bits ieeeExponent = [
68 ieeeMantissa zero? [ sign "-Inf" "Inf" ? ] [ "NaN" ] if
71 ieeeMantissa [ sign "-0e0" "0e0" ? ] [
73 -1 offset - mantissaBits - e2!
77 offset - mantissaBits - 2 - e2!
78 ieeeMantissa mantissaBits set-bit m2!
81 ] if [ e2 m2 dup even? ieeeExponent 1 <= sign ] dip ; inline
83 :: prepare-output ( vp! vplength acceptBounds vmIsTrailingZeros! vrIsTrailingZeros! vr! vm! -- vplength' output )
84 ! vr is converted into the output
86 ! the if has this stack-effect: ( lastRemovedDigit vplength -- lastRemovedDigit' vplength' output )
87 vmIsTrailingZeros vrIsTrailingZeros or [
89 [ vp 10 /i vm 10 /i 2dup > ] [
91 vmIsTrailingZeros [ vm 10 divisor? vmIsTrailingZeros! ] when
92 vrIsTrailingZeros [ over zero? vrIsTrailingZeros! ] when
93 vr 10 /mod -roll vr! nip ! lastRemovedDigit!
97 [ vm dup 10 /i dup 10 * swapd = ] [
99 vrIsTrailingZeros [ over zero? vrIsTrailingZeros! ] when
100 vr 10 /mod -roll vr! nip ! lastRemovedDigit!
103 ] while drop ! Drop (vm 10 /i) result from the while condition.
107 vr even? [ 4 -rot nip ] when ! 4 lastRemovedDigit!
110 vr pick 5 >= [ 1 + ] [
112 acceptBounds vmIsTrailingZeros and not [ 1 + ] when
117 [ vp 10 /i vm 10 /i 2dup > ] [
119 vr 10 /mod -roll vr! nip ! lastRemovedDigit!
122 vr dup vm = [ 1 + ] [
123 pick 5 >= [ 1 + ] when
127 : write-char ( index seq char -- index+1 seq' )
128 -rot [ tuck ] dip [ set-nth 1 + ] keep ; inline
130 : write-exp ( exp index result -- result' )
133 CHAR: - write-char [ neg ] 2dip
136 100 /i CHAR: 0 + write-char
138 pick DIGIT_TABLE nth write-char
139 [ 1 + DIGIT_TABLE nth ] 2dip [ set-nth ] keep
143 pick DIGIT_TABLE nth write-char
144 [ 1 + DIGIT_TABLE nth ] 2dip [ set-nth ] keep
146 [ CHAR: 0 + ] 2dip [ set-nth ] keep
150 :: produce-output ( exp sign olength output2! -- string )
151 25 <vector> 0 :> ( result i! )
152 0 sign [ CHAR: - swap result set-nth 1 ] when :> index!
153 [ output2 10000 >= ] [
154 output2 dup 10000 /i dup output2! 10000 * - :> c
155 index olength + i - 1 - :> res-index
157 dup DIGIT_TABLE nth res-index result set-nth
158 1 + DIGIT_TABLE nth res-index 1 + result set-nth
160 dup DIGIT_TABLE nth res-index 2 - result set-nth
161 1 + DIGIT_TABLE nth res-index 1 - result set-nth
165 output2 dup 100 /i dup output2! 100 * - 2 * :> c
166 index olength + i - :> res-index
167 c DIGIT_TABLE nth res-index 1 - result set-nth
168 c 1 + DIGIT_TABLE nth res-index result set-nth
173 index olength + i - :> res-index
174 c 1 + DIGIT_TABLE nth res-index result set-nth
175 c DIGIT_TABLE nth index result set-nth
176 ] [ CHAR: 0 output2 + index result set-nth ] if
179 CHAR: . index result set-nth
180 index olength + index!
181 ] when exp index result write-exp >string ; inline
185 :: print-float ( value -- string )
186 value >float unpack-bits [
188 ] [| e2 m2 acceptBounds ieeeExponent<=1 sign |
190 mantissaBits 2^ m2 = not ieeeExponent<=1 or 1 0 ? :> mmShift
191 f f 0 0 0 :> ( vmIsTrailingZeros! vrIsTrailingZeros! e10! vr! vm! )
192 ! After the following loop vp is left on stack.
194 e2 DOUBLE_LOG10_2_NUMERATOR * DOUBLE_LOG10_2_DENOMINATOR /i 0 max :> q
196 q double-pow-5-bits DOUBLE_POW5_INV_BITCOUNT + 1 - :> k
198 mmShift m2 q DOUBLE_POW5_INV_SPLIT nth i mul-shift-all vr! swap vm! ! vp on stack
201 q mv multiple-of-power-of-5 vrIsTrailingZeros!
204 q mv mmShift - 1 - multiple-of-power-of-5 vmIsTrailingZeros!
206 q mv 2 + multiple-of-power-of-5 1 0 ? - ! vp!
211 e2 neg DOUBLE_LOG10_5_NUMERATOR * DOUBLE_LOG10_5_DENOMINATOR /i 1 [-] :> q
214 i double-pow-5-bits DOUBLE_POW5_BITCOUNT - :> k
216 mmShift m2 i DOUBLE_POW5_SPLIT nth j mul-shift-all vr! swap vm! ! vp on stack
218 mv 1 bitand bitnot q >= vrIsTrailingZeros!
220 mv 1 - mmShift - bitnot 1 bitand q >= vmIsTrailingZeros!
224 q 1 - on-bits mv bitand zero? vrIsTrailingZeros!
228 dup decimal-length ! vp vplength
229 dup e10 + 1 - sign 2swap ! exp and sign for produce-output
230 acceptBounds vmIsTrailingZeros vrIsTrailingZeros vr vm
231 prepare-output produce-output
234 ALIAS: d2s print-float