Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.forth    |    Forth programmers eat a lot of Bratwurst    |    117,927 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 116,489 of 117,927    |
|    Krishna Myneni to All    |
|    F*/ (f-star-slash) (1/2)    |
|    19 May 24 16:28:12    |
   
   From: krishna.myneni@ccreweb.org   
      
   The analog of */ for single length integers, with intermediate double   
   length result, can be implemented for floating point arithmetic as well.   
   The following implementation of F*/ uses the non-standard word, UD/MOD,   
   although it might be possible to code it with UM/MOD as well. It also   
   requires FP@ (requiring a separate fp stack in memory).   
      
   How is F*/ different from using F* and F/ sequentially?   
      
   Consider the following cases:   
      
   1) 1.0e300 -3.0e259 F* 1.0e280 F/   
      
   2) 1.0e-300 3.0e-259 F* 1.0e-280 F/   
      
   3) 1.0e302 -3.0e302 F* DP_+INF F/   
      
   4) -1.0e-302 -1.0e-302 F* 0.0e0 F/   
      
   (DP_+INF is the double-precision IEEE-754 representation of plus infinity).   
      
   The first two cases, on a double-precision FP system, result in -inf and   
   zero, respectively.   
      
   Cases 3 and 4 result in NaN (not a number).   
      
   A proper implementation of F*/ can evaluate the result to a number for   
   cases 1 and 2, recognizing that the final result is representable as a   
   double-precision number. For cases 3 and 4 F*/ recognizes that the final   
   results are signed zero and +INF. F*/ represents the intermediate result   
   of the product with a wider number representation.   
      
   The code below, which requires a separate FP stack in memory, has been   
   tested on kForth-64 and Gforth. Gforth appears to have a problem   
   representing signed zero, although it does represent plus and minus   
   infinity.   
      
   1.0e302 -3.0e302 DP_+INF f*/ fs. 0.00000000000000E0 ok   
      
   ( should be minus zero in the above case).   
      
   The factor of _F*/ was done on purpose, to be used as a basis for higher   
   precision calculations.   
      
   The tests do not include subnormal number testing or for NANs at the   
   present time.   
      
   --   
   Krishna Myneni   
      
   === start of fstarslash.4th ===   
   \ fstarslash.4th   
   \   
   \ Implementation of F*/ on 64-bit Forth   
   \   
   \ Krishna Myneni, 2024-05-19   
   \   
   \ F*/ ( F: r1 r2 r3 -- r )   
   \ Multiply two IEEE-754 double precision floating point   
   \ numbers r1 and r2 and divide by r3 to obtain the result,   
   \ r. The intermediate product significand, r1*r2, is   
   \ represented with at least IEEE quad precision for both   
   \ its significand and exponent.   
   \   
   \ F*/ uses an intermediate significand represented by   
   \ 128 bits   
   \   
      
   include ans-words   
      
   1 cells 8 < [IF]   
    cr .( Requires 64-bit Forth system ) cr   
    ABORT   
   [THEN]   
      
   fvariable temp   
   : >fpstack ( u -- ) ( F: -- r )   
    temp ! temp f@ ;   
      
   base @ hex   
   8000000000000000 constant DP_SIGNBIT_MASK   
   000FFFFFFFFFFFFF constant DP_FRACTION_MASK   
   7FF0000000000000 constant DP_EXPONENT_MASK   
   \ DP special value constants   
   7FF0000000000001 >fpstack fconstant DP_NAN   
   FFF0000000000000 >fpstack fconstant DP_-INF   
   7FF0000000000000 >fpstack fconstant DP_+INF   
   base !   
      
    52 constant DP_FRACTION_BITS   
   1023 constant DP_EXPONENT_BIAS   
   2047 constant DP_EXPONENT_MAX   
      
   1 DP_FRACTION_BITS LSHIFT constant DP_IMPLIED_BIT   
   63 constant DP_SIGN_BIT   
      
   : dp-fraction ( F: r -- r ) ( -- u )   
    FP@ @ DP_FRACTION_MASK and ;   
   : dp-exponent ( F: r -- r ) ( -- e )   
    FP@ @ DP_EXPONENT_MASK and DP_FRACTION_BITS rshift ;   
   : dp-sign ( F: r -- r ) ( -- sign )   
    FP@ @ DP_SIGN_BIT rshift ;   
      
   : _isZero? ( ufrac uexp -- b ) 0= swap 0= and ;   
   : _isInf? ( ufrac uexp -- b ) DP_EXPONENT_MAX = swap 0= and ;   
   : _isNaN? ( ufrac uexp -- b ) DP_EXPONENT_MAX = swap 0<> and ;   
   : _isSubNormal? ( ufrac uexp -- b ) 0= swap 0<> and ;   
      
   : frac>significand ( u -- u' ) DP_IMPLIED_BIT or ;   
      
   \ Show the significand, unbiased base-2 exponent, and sign bit   
   \ for a double-precision floating point number. To recover the   
   \ dp floating point number, r, from these fields,   
   \   
   \ r = (-1)^sign * significand * 2^(exponent - 52)   
   \   
   : dp-components. ( F: r -- )   
    dp-sign   
    dp-exponent   
    dp-fraction   
    2dup D0= invert IF frac>significand THEN   
    swap DP_EXPONENT_BIAS - swap   
    fdrop   
    ." significand = " 18 u.r 2 spaces   
    ." exponent = " 4 .r 2 spaces   
    ." sign = " .   
      
      
   : dp-normal-fraction ( u -- expinc u')   
    dup DP_FRACTION_BITS 1+ rshift   
    dup IF   
    tuck rshift   
    ELSE   
    drop -1 swap \ -1 u   
    BEGIN   
    1 lshift   
    dup DP_IMPLIED_BIT and 0=   
    WHILE   
    swap 1- swap   
    REPEAT   
    THEN   
      
      
    0 value r1_sign   
    0 value r2_sign   
    0 value r3_sign   
    0 value num_sign   
   variable r1_exp   
   variable r2_exp   
   variable r3_exp   
   variable r_exp   
   variable r1_frac   
   variable r2_frac   
   variable r3_frac   
      
   : get-arg-components ( F: r1 r2 r3 -- )   
    dp-fraction r3_frac !   
    dp-exponent r3_exp !   
    dp-sign to r3_sign   
    fdrop   
    dp-fraction r2_frac !   
    dp-exponent r2_exp !   
    dp-sign to r2_sign   
    fdrop   
    dp-fraction r1_frac !   
    dp-exponent r1_exp !   
    dp-sign to r1_sign   
    fdrop ;   
      
   0 value b_num_zero   
   0 value b_den_zero   
   0 value b_num_Inf   
   0 value b_den_Inf   
      
   variable remainder   
      
   : _F*/ ( F: r1 r2 r3 -- ) ( -- usign uexponent udfraction true )   
    \ or ( F: -- DP_NAN | +/- DP_INF ) ( -- false )   
    get-arg-components   
      
    \ Check for NaN in args   
    r1_frac @ r1_exp @ _IsNaN?   
    r2_frac @ r2_exp @ _IsNaN? or   
    r3_frac @ r3_exp @ _IsNaN? or IF DP_NAN FALSE EXIT THEN   
      
    r1_frac @ r1_exp @ _IsZero?   
    r2_frac @ r2_exp @ _IsZero? or to b_num_zero   
    r3_frac @ r3_exp @ _IsZero? to b_den_zero   
      
    b_num_zero b_den_zero and IF DP_NAN FALSE EXIT THEN   
      
    r1_sign r2_sign xor to num_sign   
      
    r1_frac @ r1_exp @ _IsInf?   
    r2_frac @ r2_exp @ _IsInf? or to b_num_Inf   
    r3_frac @ r3_exp @ _IsInf? to b_den_Inf   
      
    b_num_Inf b_den_Inf and IF DP_NAN FALSE EXIT THEN   
      
    b_num_zero b_den_Inf or IF \ return signed zero   
    num_sign r3_sign xor   
    0   
    0 s>d TRUE EXIT   
    THEN   
      
    b_den_zero b_num_Inf or IF \ return signed Inf   
    DP_+INF   
    num_sign r3_sign xor IF FNEGATE THEN   
    FALSE EXIT   
    THEN   
      
    num_sign r3_sign xor   
    r1_exp @ r2_exp @ + r3_exp @ -   
    r1_frac @ frac>significand   
    r2_frac @ frac>significand um*   
    r3_frac @ frac>significand ud/mod   
    rot remainder !   
    TRUE   
      
      
   variable uhigh   
      
   : F*/ ( F: r1 r2 r3 -- r )   
    _F*/ \ ( -- usign uexp udfrac true ) or   
    \ ( -- false ) ( F: NAN | +/-INF )   
    IF   
    2 pick 0 DP_EXPONENT_MAX WITHIN 0= IF   
    -43 throw   
    THEN   
    dup IF \ high 64 bits of the quotient   
    uhigh !   
    -43 throw   
    ELSE   
    drop   
    2dup D0= IF \ ufrac = 0 and uexp 0   
    drop \ usign uexp   
    ELSE   
    \ usign   
    \ quotient: normal double precision fraction   
    dp-normal-fraction \ usign uexp expinc uquot   
    >r + DP_FRACTION_BITS lshift r> or   
    THEN   
    swap DP_SIGN_BIT lshift or   
    >fpstack   
    THEN   
    THEN   
      
      
   \ Tests   
   1 [IF]   
   [UNDEFINED] T{ [IF] include ttester.4th [THEN]   
   1e-17 rel-near f!   
   1e-17 abs-near f!   
   TESTING F*/   
      
   [continued in next message]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca