Guest User

Double-double floating-point package for Forth

a guest
Sep 4th, 2026
29
0
311 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.45 KB | Source Code | 0 0
  1. \ Modified for KForth
  2.  
  3. [UNDEFINED] DXFORTH [IF]
  4.  
  5. : SYSTEM ;
  6. : APPLICATION ;
  7.  
  8. \ : \\ SOURCE-ID IF BEGIN REFILL 0= UNTIL THEN ;
  9.  
  10. : END POSTPONE EXIT POSTPONE THEN ; IMMEDIATE
  11.  
  12. : /CHAR ( a u -- a2 u2 c ) 1 /STRING OVER 1- C@ ;
  13.  
  14. : >DIGIT ( char base -- u true | char 0 )
  15. OVER [CHAR] 0 - DUP 10 17 WITHIN 0= IF DUP 16 U>
  16. IF 7 - THEN DUP ROT U< IF NIP TRUE END DUP THEN
  17. 2DROP FALSE ;
  18.  
  19. : >CHAR ( u -- char ) DUP 9 > IF 7 + THEN [CHAR] 0 + ;
  20.  
  21. : (NUMBER) 0 0 2SWAP >NUMBER ;
  22.  
  23. : /SIGN ( a u -- a' u' f )
  24. DUP IF OVER C@ DUP [CHAR] + = SWAP [CHAR] - =
  25. DUP >R OR NEGATE /STRING R> END 0 ;
  26.  
  27. : /NUMBER ( a u -- a' u' d|ud )
  28. /SIGN >R (NUMBER) 2SWAP R> IF DNEGATE THEN ;
  29.  
  30. : TOKEN BL WORD COUNT ;
  31.  
  32. [THEN]
  33.  
  34.  
  35. \ DDFLOAT.F
  36.  
  37. \ Doubled-precision floating point arithmetic
  38. \
  39. \ Reference
  40. \
  41. \ JVN's 128-bit Forth floating point arithmetic package:
  42. \ http://galileo.phys.virginia.edu/classes/551.jvn.fall01/ddarith.htm
  43. \ http://galileo.phys.virginia.edu/classes/551.jvn.fall01/dd_io.htm
  44. \
  45. \ 2026-09-05 changes:
  46. \
  47. \ - renamed package to DDFLOAT so you know who to blame
  48. \ - fix bugs in DDFS.
  49. \ - replace input routine >DD
  50. \ - rename r128! r128@ real*16 to DD! DD@ DDVARIABLE
  51. \ - add DD< DD> DD= DDLITERAL (DDFS.)
  52. \ - remove separate float stack requirement
  53. \
  54. \ Material not (c) Julian V. Noble is hereby placed
  55. \ in the PUBLIC DOMAIN. Use at your own risk.
  56.  
  57. \ ---------------------------------------------------
  58. \ (c) Copyright 2006 Julian V. Noble. \
  59. \ Permission is granted by the author to \
  60. \ use this software for any application pro- \
  61. \ vided this copyright notice is preserved. \
  62. \ ---------------------------------------------------
  63.  
  64. \ This is an ANS Forth program requiring the
  65. \ FLOAT, FLOAT EXT, FILE and TOOLS EXT wordsets.
  66. \
  67. \ Environmental dependences:
  68. \ Assumes independent floating point stack
  69. \ the fpu must be set to 64-bit internal operations
  70. \ ^^^^
  71.  
  72. CR .( Double-Double Precision FP) CR
  73.  
  74. 1 FLOATS 8 - [IF]
  75. CR .( ERROR: Requires Double-Precision FP system) ABORT \\
  76. [THEN]
  77.  
  78. \ MARKER -double
  79.  
  80. [UNDEFINED] F>S [IF] : F>S F>D D>S ; [THEN]
  81. [UNDEFINED] S>F [IF] : S>F S>D D>F ; [THEN]
  82. [UNDEFINED] FTUCK [IF] : FTUCK FSWAP FOVER ; [THEN]
  83. [UNDEFINED] F-ROT [IF] : F-ROT FROT FROT ; [THEN]
  84.  
  85.  
  86. \ ---------------------------------------- LOAD, STORE
  87. : DD@ ( adr -- dd ) DUP >R F@ R> FLOAT+ F@ ;
  88. : DD! ( dd adr -- ) DUP >R FLOAT+ F! R> F! ;
  89. \ ------------------------------------ END LOAD, STORE
  90.  
  91. \ ----------------------------------- data types ----
  92. SYSTEM
  93.  
  94. : DDVARIABLE \ create a double-double variable
  95. \ FALIGN HERE 2 FLOATS ALLOT CONSTANT ;
  96. CREATE 2 DFLOATS ALLOT ;
  97.  
  98. : DDCONSTANT \ create a double-double constant
  99. \ CREATE FALIGN HERE 2 FLOATS ALLOT DD!
  100. \ DOES> FALIGNED DD@ ;
  101. CREATE 2 FLOATS ALLOT? dd!
  102. DOES> DD@ ;
  103.  
  104. : DDLITERAL
  105. FSWAP POSTPONE FLITERAL POSTPONE FLITERAL
  106. ; IMMEDIATE
  107.  
  108. APPLICATION
  109. \ ---------------------------------------------------
  110.  
  111. 3.1415926535897931e0 1.2246467991473532e-16 DDCONSTANT DDPI
  112.  
  113. \ = 3.141592653589793238462643383279
  114. \ pi = 3.1415926535897932384626433832795028841971693993751...
  115.  
  116.  
  117. \ based on "Software for Doubled-Precision Floating-Point Computations"
  118. \ by Seppo Linnainmaa
  119. \ ACM Transactions on Mathematical Software,
  120. \ Vol 7, No 3, September 1981, Pages 272-283
  121.  
  122. FALSE [IF] \ determine base and precision of fpu
  123.  
  124. 4e0 3e0 F/ 1e0 F- 3e0 F* 1e0 F- FVALUE u
  125. u 2e0 F/ 1e0 F+ 1e0 F- FVALUE r
  126. r F0= NOT [IF] r FTO u [THEN]
  127. 2e0 3e0 F/ 0.5e0 F- 3e0 F* 0.5e0 F- FVALUE uu
  128. uu 2e0 F/ 0.5e0 F+ 0.5e0 F- FVALUE rr
  129. rr F0= NOT [IF] rr FTO uu [THEN]
  130. u uu F/ ( f: -- beta)
  131. uu FLN FOVER FLN F/ FNEGATE 0.5e0 F+
  132. F>S F>S CR CR .( base = ) . .( precision = ) . FORGET u
  133.  
  134. [THEN]
  135.  
  136. \ Exact multiplication
  137.  
  138. \ 134217729. D>F FCONSTANT split
  139. 134217729 S>F FCONSTANT split
  140.  
  141. fvariable t fvariable a1 fvariable a2 fvariable b1
  142. fvariable b2 fvariable b21 fvariable b22 fvariable ta
  143. fvariable tb
  144.  
  145. fvariable q fvariable qq fvariable x fvariable xx
  146. fvariable y fvariable yy fvariable z1 fvariable z2
  147.  
  148. fvariable aaa fvariable bbb
  149.  
  150. : exactmul ( f: a b -- x xx) \ multiply 2 fp#'s to get ddfp#
  151. aaa F! bbb F!
  152. bbb F@ split F* t F!
  153. t F@ bbb F@ FOVER F- F+ FDUP a1 F! ( f: a1)
  154. FNEGATE bbb F@ F+ a2 F!
  155. aaa F@ FDUP split F* t F! ( f: aaa)
  156. t F@ ftuck F- F+ b1 F!
  157. aaa F@ b1 F@ F- FDUP FDUP b2 F! ( f: b2 b2)
  158. split F* t F!
  159. t F@ ftuck F- F+ FDUP b21 F! ( f: b21)
  160. FNEGATE b2 F@ F+ b22 F!
  161. bbb F@ aaa F@ F* FDUP t F!
  162. a1 F@ b1 F@ F* t F@ F- a1 F@ b2 F@ F*
  163. F+ b1 F@ a2 F@ F* F+
  164. b21 F@ a2 F@ F* F+ b22 F@ a2 F@ F* F+
  165. ;
  166.  
  167. : DD/ ( f: x xx y yy -- [x+xx]/[y+yy] )
  168. yy F! y F! xx F! x F!
  169. y F@ FABS F0= ABORT" Can't divide by 0!"
  170. x F@ y F@ F/ FDUP z1 F!
  171. y F@ exactmul qq F! FDUP q F! ( f: q)
  172. FNEGATE x F@ F+ qq F@ F-
  173. xx F@ F+ z1 F@ yy F@ F* F-
  174. y F@ yy F@ F+ F/ FDUP z2 F!
  175. z1 F@ F+ FDUP
  176. FNEGATE z1 F@ F+ z2 F@ F+
  177. ;
  178.  
  179. : DD* ( f: x xx y yy -- [x+xx]*[y+yy] )
  180. yy F! y F! xx F! x F!
  181. x F@ y F@ exactmul qq F! z1 F!
  182. x F@ xx F@ F+ yy F@ F*
  183. xx F@ y F@ F* F+ qq F@ F+ FDUP z2 F!
  184. z1 F@ F+ FDUP
  185. FNEGATE z1 F@ F+ z2 F@ F+
  186. ;
  187.  
  188. : DD+ ( f: x xx y yy -- [x+xx] + [y+yy] )
  189. yy F! y F! xx F! x F!
  190. x F@ y F@ F+ z1 F!
  191. x F@ z1 F@ F- FDUP q F!
  192. y F@ F+ ( f: q+y)
  193. x F@ q F@ z1 F@ F+ F- ( f: q+y x-[q+z1])
  194. F+ xx F@ F+ yy F@ F+ FDUP z2 F!
  195. z1 F@ F+ FDUP ( f: z1+z2 z1+z2)
  196. FNEGATE z1 F@ F+ z2 F@ F+
  197. ;
  198.  
  199. : DDNEGATE ( f: x xx -- -x -xx)
  200. FNEGATE FSWAP FNEGATE FSWAP
  201. ;
  202.  
  203. : DD- ( f: x xx y yy -- [x+xx] - [y+yy] )
  204. DDNEGATE DD+
  205. ;
  206.  
  207. \ Square root based on T.J. Dekker,
  208. \ "A Floating-Point Technique for Extending the Available Precision"
  209. \ Numerische Mathematik 18 (1971) 224-242.
  210.  
  211. : DDSQRT ( f: x xx -- ddsqrt[x+xx])
  212. xx F! FDUP x F!
  213. F0< ABORT" Can't take sqrt of negative number!"
  214. x F@ FSQRT FDUP q F!
  215. FDUP exactmul yy F! FDUP y F!
  216. FNEGATE x F@ F+
  217. yy F@ F- xx F@ F+
  218. 0.5e0 F* q F@ F/ FDUP qq F!
  219. q F@ F+ FDUP
  220. FNEGATE q F@ F+ qq F@ F+
  221. ;
  222.  
  223. \ ----------------------------------- stack ops -----
  224. FVARIABLE dtemp
  225.  
  226. DDVARIABLE ddtemp DDVARIABLE ddtemp1
  227.  
  228. : DDSWAP ( f: x xx y yy -- y yy x xx )
  229. dtemp F! F-ROT dtemp F@ F-ROT ;
  230.  
  231. : DDDUP FOVER FOVER ;
  232.  
  233. : DDDROP FDROP FDROP ;
  234.  
  235. : DDOVER ddtemp DD! dddup ddtemp1 DD!
  236. ddtemp DD@ ddtemp1 DD@ ;
  237.  
  238. : DDTUCK ddtemp DD! ddtemp1 DD!
  239. ddtemp DD@ ddtemp1 DD@
  240. ddtemp DD@ ;
  241.  
  242. fvariable a3 fvariable a4 fvariable b3 fvariable b4
  243.  
  244. : ddcomp ( a3 a4 b3 b4 -- -1|0|1 )
  245. b4 F! b3 F! a4 F! a3 F!
  246. a3 F@ b3 F@ F< IF -1 EXIT THEN
  247. a3 F@ b3 F@ F= IF
  248. a4 F@ b4 F@ F< IF -1 EXIT THEN
  249. a4 F@ b4 F@ F= IF 0 EXIT THEN
  250. THEN 1 ;
  251.  
  252. : DD< ( dd1 dd2 -- f ) ddcomp -1 = ;
  253. : DD> ( dd1 dd2 -- f ) ddcomp 1 = ;
  254. : DD= ( dd1 dd2 -- f ) ddcomp 0= ;
  255.  
  256. \ ---------------------------------------------------
  257.  
  258. 1e0 0e0 DDCONSTANT dd1.
  259. 10e0 0e0 DDCONSTANT dd10.
  260.  
  261. : DD^2 ( x xx -- [x+xx]^2 )
  262. dddup dd* ;
  263.  
  264. : DD^N ( x xx n -- [x+xx]^n )
  265. \ raise dd to integer power
  266. \ return 1 if n=0, dd^{-|n|} if n<0
  267. >R
  268. dd1. DDSWAP ( f1e0 0e0 x xx )
  269. R> DUP 0= IF DROP DDDROP EXIT THEN
  270. DUP 0< >R ( sign) ABS ( |n| )
  271. BEGIN DUP 0> WHILE
  272. DUP >R 1 AND IF DDTUCK DD* DDSWAP THEN dd^2
  273. R> 2/
  274. REPEAT DROP DDDROP
  275. R> IF dd1. DDSWAP DD/ THEN
  276. ;
  277.  
  278. \ Input routine adapted from:
  279. \ http://dxforth.webhop.org/finput.html
  280.  
  281. VARIABLE exp \ exponent
  282. VARIABLE dpf \ decimal point
  283.  
  284. DDVARIABLE tmp
  285.  
  286. : /digs ( a u -- a' u' )
  287. BEGIN DUP WHILE
  288. /CHAR 10 >DIGIT WHILE
  289. S>F 0.0E tmp DD@ dd10. DD* DD+ tmp DD!
  290. dpf @ exp +!
  291. REPEAT DROP -1 /STRING THEN ;
  292.  
  293. : /mant ( a u -- a' u' flag )
  294. TUCK /digs DUP IF
  295. OVER C@ [CHAR] . = IF
  296. -1 dpf ! 1 /STRING /digs
  297. THEN
  298. THEN ROT OVER - dpf @ + ;
  299.  
  300. : /exp ( a u -- a' u' )
  301. DUP IF
  302. OVER C@ 33 OR [CHAR] e = ( 'D' 'E' 'd' 'e')
  303. 1 AND /STRING
  304. THEN
  305. /NUMBER DROP exp @ +
  306. BEGIN ?DUP WHILE DUP 0<
  307. IF 1+ tmp DD@ dd10. DD/
  308. ELSE 1- tmp DD@ dd10. DD* THEN tmp DD!
  309. REPEAT ;
  310.  
  311. \ Like >FLOAT but returns a dd number
  312. : >DD ( c-addr u -- dd true | false )
  313. 0.0E 0.0E tmp DD! 0 exp ! 0 dpf !
  314. -TRAILING /SIGN >R DUP IF
  315. /mant IF /exp THEN
  316. ELSE 0= THEN
  317. NIP IF R> DROP 0 END
  318. tmp DD@ R> IF DDNEGATE THEN TRUE ;
  319.  
  320. SYSTEM
  321.  
  322. \ Interpret/compile dd number
  323. : DD# ( "number" )
  324. TOKEN >DD 0= ABORT" bad float"
  325. STATE @ IF POSTPONE DDLITERAL THEN ; IMMEDIATE
  326.  
  327. APPLICATION
  328.  
  329. [DEFINED] DXFORTH [IF] BEHEAD exp getexp [THEN]
  330.  
  331.  
  332. \ This is an ANS Forth program requiring the
  333. \ FLOAT, FLOAT EXT, FILE and TOOLS EXT wordsets.
  334. \
  335. \ Environmental dependences:
  336. \ Assumes independent floating point stack
  337.  
  338. \ Based on I/O subroutines from
  339. \
  340. \ DDFUN: A Double-Double Floating Point Computation Package
  341. \ IEEE Fortran-90 version
  342. \ Version Date: 2005-01-26
  343. \
  344. \ Author:
  345. \
  346. \ David H. Bailey
  347. \ NERSC, Lawrence Berkeley Lab
  348. \ Mail Stop 50B-2239
  349. \ Berkeley, CA 94720
  350.  
  351. \ Output a dd# .
  352.  
  353. \ Algorithm:
  354. \
  355. \ 1. Determine sign and power of 10
  356. \ 2. Normalize so that significand lies between 1 and <10
  357. \ 3. Peel digits off from left by converting to integer
  358. \ multiplying by dd10 and repeating
  359. \ 4. Construct output string digit by digit, append
  360. \ sign and exponent, and display.
  361.  
  362. : getsign ( x xx -- x xx f )
  363. FOVER F0< ;
  364.  
  365. : getpower ( x xx -- x xx n)
  366. FOVER FABS FLOG
  367. FLOOR F>S ;
  368.  
  369. : normalize ( x xx n -- y yy n')
  370. >R
  371. getsign IF DDNEGATE THEN ( |x| |xx| )
  372. dd10. R@ DD^N DD/ ( [|x|+|xx|]/10^n )
  373.  
  374. \ make sure it's between 1 and <10
  375. BEGIN DDDUP dd10. DD< 0=
  376. WHILE dd10. DD/ R> 1+ >R REPEAT
  377.  
  378. BEGIN DDDUP dd1. DD<
  379. WHILE dd10. DD* R> 1- >R REPEAT
  380. R>
  381. ;
  382.  
  383. CREATE digits 32 CELLS ALLOT
  384.  
  385. : copydigits ( -- ) \ to HOLD buffer
  386. 1 CELLS digits + 31 CELLS digits + DO
  387. I @ 0< IF 10 I +! -1 I 1 CELLS - +! THEN \ fix negative
  388. I @ >CHAR HOLD
  389. -1 CELLS +LOOP [char] . HOLD digits @ >CHAR HOLD
  390. ;
  391.  
  392. : peeldigits ( y yy -- ) \ to array
  393. digits 32 0 DO >R
  394. FOVER F>S R> 2DUP ! 1 CELLS + >R
  395. S>F 0e0 DD- dd10. DD* R>
  396. LOOP DROP DDDROP
  397. ;
  398.  
  399. : (DDFS.) ( dd -- c-addr u ) \ string double-double in E-format
  400. FOVER F0= IF
  401. 0 0 >R
  402. ELSE
  403. getsign >R
  404. getpower ( x xx n)
  405. normalize ( y yy n')
  406. THEN
  407. DUP ABS S>D \ convert exponent
  408. <# #S 2DROP SIGN \ append digits of exponent
  409. [char] E HOLD
  410. peeldigits copydigits
  411. R> IF [char] - HOLD THEN 0 0 #>
  412. ;
  413.  
  414. : DDFS. ( dd -- ) \ display double-double in E-format
  415. (DDFS.) TYPE SPACE ;
  416.  
  417. [DEFINED] DXFORTH [IF]
  418. BEHEAD split exactmul
  419. BEHEAD dtemp ddtemp1
  420. BEHEAD a3 ddcomp
  421. BEHEAD dd1. dd10.
  422. BEHEAD getsign peeldigits
  423. [THEN]
  424.  
  425.  
  426. 1 [IF] CR .( Testing ) CR
  427.  
  428. : test ( a u -- ) 2DUP >DD
  429. CR IF DDFS. 2DROP ELSE TYPE ." failed" THEN ;
  430.  
  431. s" -11.1112222233333444445555566666d-45" test
  432.  
  433. s" +-11.1112222233333444445555566666d-45" test
  434. \ Error: >dd Non-digit in significand!
  435.  
  436. s" +11.1112222.233333444445555566666d-45" test
  437. \ Error: >dd One dp to a customer!
  438.  
  439. s" +11.1112222233333444445555566666d+45" test
  440. \ +1.1111222223333344444555556666604 dd 46 ok
  441.  
  442. s" +11.1112222233333444445555566666" test
  443. \ 0.0000000000000000000000000000000 dd 0 ok
  444. \ <- Must have exponent field (N/A in this version)
  445.  
  446. s" +11.1112222233333444445555566666d" test
  447. \ +1.1111222223333344444555556666603 dd 1 ok
  448.  
  449. s" +11.1112222233333444445555566666D" test
  450. \ +1.1111222223333344444555556666603 dd 1 ok
  451.  
  452. s" 1111122.222333D" test
  453. \ +1.1111222223330000000000000000000 dd 6 ok
  454.  
  455. CR
  456.  
  457. DD# 0 CR DDFS.
  458. DD# 2 DD# 3 DD/ CR DDFS.
  459. DD# 9.9999999999999999999999987654321e CR DDFS.
  460. DD# -9.9999999999999900000000123456789e CR DDFS.
  461. DD# -9.999999999999e CR DDFS.
  462.  
  463. [THEN]
  464.  
Advertisement
Add Comment
Please, Sign In to add comment