home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 2.ddi / CLIBSRC3.ZIP / BCD1.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  7.5 KB  |  354 lines

  1. /*-----------------------------------------------------------------------*
  2.  * filename - bcd1.c
  3.  * Library for long double / binary code decimal conversions
  4.  *-----------------------------------------------------------------------*/
  5.  
  6. /*
  7.  *      C/C++ Run Time Library - Version 5.0
  8.  *
  9.  *      Copyright (c) 1987, 1992 by Borland International
  10.  *      All Rights Reserved.
  11.  *
  12.  */
  13.  
  14.  
  15. #include <_defs.h>
  16.  
  17. /*
  18. about 17 digits precision
  19. exponent range, about 1e-125 to 1e+125
  20.  
  21. bcd format:
  22. expo            mantissa                value
  23. 0               0                       0
  24. 1               +1 or -1                +INF or -INF
  25. 2               ?                       NAN
  26. 3-255           x                       x * 10 ^ (expo - Bias)
  27.  
  28. The Bias is 147, so exponent range is 3-147=-144 to 255-147=+108.
  29. Caution: The decimal representation is not unique.
  30. Eg, { 1L, 0L, 1+Bias } is the same as { 10L, 0L, 0+Bias }.
  31. */
  32.  
  33. #pragma  inline
  34.  
  35. typedef unsigned short bits16;
  36.  
  37. typedef struct
  38. {
  39.     bits16      frac [4];
  40.     bits16      signExp;
  41. }
  42.     IEEE80;
  43.  
  44. struct decimal {
  45.         long mantissa[2];
  46.         short expo;
  47. };
  48.  
  49. typedef struct decimal bcd;
  50.  
  51. enum bcdexpo {
  52.         ExpoZero,
  53.         ExpoInf,
  54.         ExpoNan,
  55. };
  56.  
  57. #define Bias    147
  58.  
  59. #define I asm
  60.  
  61. #define REAL    qword ptr
  62. #define REAL1   dword ptr
  63. #define REAL2   qword ptr
  64. #define REAL3   tbyte ptr
  65.  
  66. #define BYTE    byte ptr
  67. #define WORD    word ptr
  68. #define LONG    dword ptr
  69. #define LONG64  qword ptr
  70.  
  71. static const long e0toF [8] =
  72. {
  73.     1, 10, 100, 1000, 10000, 100000L, 1000000L, 10000000L
  74. };
  75.  
  76. static const IEEE80 expo [10] =
  77. {
  78.     {{0,      0,      0x2000, 0xBEBC}, 0x4019},    /* 1e8    */
  79.     {{0,      0x0400, 0xC9BF, 0x8E1B}, 0x4034},    /* 1e16   */
  80.     {{0xB59E, 0x2B70, 0xADA8, 0x9DC5}, 0x4069},    /* 1e32   */
  81.     {{0xA6D5, 0xFFCF, 0x1F49, 0xC278}, 0x40D3},    /* 1e64   */
  82.     {{0x8CE0, 0x80E9, 0x47C9, 0x93BA}, 0x41A8},    /* 1e128  */
  83.     {{0xDE8E, 0x9DF9, 0xEBFB, 0xAA7E}, 0x4351},    /* 1e256  */
  84.     {{0x91C7, 0xA60E, 0xA0AE, 0xE319}, 0x46A3},    /* 1e512  */
  85.     {{0x0C17, 0x8175, 0x7586, 0xC976}, 0x4D48},    /* 1e1024 */
  86.     {{0x5DE5, 0xC53D, 0x3B5D, 0x9E8B}, 0x5A92},    /* 1e2048 */
  87.     {{0x979B, 0x8A20, 0x5202, 0xC460}, 0x7525},    /* 1e4096 */
  88. };
  89.  
  90. static void near pascal scale10(int p)
  91. /* return
  92.         TOS *= 10 ^ p
  93.         preserves ax! (except in HUGE)
  94. */
  95. {
  96. I       mov     si, p
  97. I       or      si, si
  98. I       mov     dx, si
  99. I       jz      scale_num
  100. I       jns     scale_abs
  101. I       neg     si
  102. scale_abs:
  103. I       cmp     si, 4999
  104. I       jbe     scale_max
  105. I       mov     si, 4999
  106. scale_max:
  107. /* load e0toF[_SI & 7] */
  108. I       mov     bx, 7
  109. I       and     bx, si
  110. I       shl     bx, 1
  111. I       shl     bx, 1
  112. I       add     bx, offset e0toF
  113. I       fild    LONG [bx]
  114.  
  115. I       mov     cl, 3
  116. I       shr     si, cl
  117. I       mov     di, offset expo
  118. expo_loop:
  119. I       or      si, si
  120. I       jz      scale_num
  121. I       shr     si, 1
  122. I       jnc     expo_next
  123. I       fld     REAL3 [di]
  124. I       fmul
  125.  
  126. expo_next:
  127. I       add     di, 10
  128. I       jmp     expo_loop
  129.  
  130. scale_num:
  131. I       or      dx, dx
  132. I       jz      scale_end
  133. I       jns     scale_mul
  134. I       fdiv
  135. I       jmp     short scale_end
  136. scale_mul:
  137. I       fmul
  138.  
  139. scale_end:
  140.         return;
  141. }
  142.  
  143. static const float inf = 1.0/0.0;
  144. static const float nan = 0.0/0.0;
  145.  
  146. /*
  147. Convert a decimal number to binary.
  148. */
  149.  
  150. long double pascal _FARFUNC __bcd_tobinary(const bcd far *p)
  151. {
  152. I       les     bx, p
  153. I       fild    LONG64 es:[bx]          /* p->mantissa */
  154. I       mov     ax, es:[bx+8]           /* p->expo */
  155.  
  156. I       cmp     al, 2
  157. I       jbe     special
  158. I       sub     ax, Bias
  159. #ifdef __HUGE__
  160. I   push ax
  161. #endif
  162.         scale10(_AX);           /* Preserves AX except in huge model */
  163. #ifdef __HUGE__
  164. I   pop ax
  165. #endif
  166. I       jmp     short done
  167.  
  168. special:
  169. I       je      nan
  170. I       or      al, al
  171. I       jz      zero
  172.  
  173. I       fmul    REAL1 inf               /* mantissa was +1 or -1 */
  174. I       jmp     short done
  175.  
  176. nan:
  177. I       fstp    st(0)
  178. I       fld     REAL1 nan
  179.         /* fall thru */
  180.  
  181. zero:
  182. /* assume mantissa is 0 */
  183. done:
  184. #pragma warn -rvl       /* Function should return a value */
  185.         return;
  186. #pragma warn .rvl       /* Function should return a value */
  187. }
  188.  
  189. /*
  190. round x to n decimal places
  191. fixed point!
  192. eg,
  193. x = 123.4567;
  194. round(x, 0) = 123.
  195. round(x, 1) = 123.5
  196. round(x, 2) = 123.46
  197. round(x, -1) = 120.
  198. round(x, -2) = 100.
  199.  
  200. uses banker's rounding
  201.  
  202. Convert a binary number to decimals.
  203. Use at most 'decimals' after the decimal point.
  204. For maximum accuracy, use decimals=5000.
  205. */
  206.  
  207. void pascal _FARFUNC __bcd_todecimal(long double x, int decimals, bcd far *p)
  208. {
  209. I       mov     ax, x[8]
  210. I       mov     dx, x[6]
  211. I       mov     cx, 7FFFh
  212. I       les     si, p
  213.  
  214. I       and     ax, cx
  215. I       jz      zero
  216. I       cmp     ax, cx
  217. I       je      special
  218.  
  219. I       sub     ax, 3FFFh + 60
  220. I       neg     ax
  221.  
  222. #if 0
  223. I       shl     dx, 1
  224. I       shl     dx, 1
  225. I       rcl     ax, 1
  226. I       shl     dx, 1
  227. I       rcl     ax, 1
  228.  
  229. I       mov     dx, 92A0h shr 1
  230. I       imul    dx
  231.  
  232. I       xchg    ax, dx
  233. I       sar     ax, 1
  234. I       sar     ax, 1
  235.  
  236. #else
  237. I       mov     dx, 9A20h shr 1 /* log10(2) */
  238. I       imul    dx
  239. I       xchg    ax, dx
  240. #endif
  241.  
  242. /* use min(ax,n) */
  243. I       mov     dx, decimals
  244. I       cmp     ax, dx
  245. I       jl      min
  246. I       xchg    ax, dx
  247. min:
  248.  
  249. /* -ax is unbiased exponent, not special, so -144 <= -ax <= 108 */
  250. I       cmp     ax, +144
  251. I       jg      underflow
  252. I       cmp     ax, -108
  253. I       jl      overflow
  254.  
  255. I       fld     REAL3 x
  256. #ifdef __HUGE__
  257. I   push ax
  258. #endif
  259.         scale10(_AX);           /* Preserves AX except in huge model */
  260. #ifdef __HUGE__
  261. I   pop ax
  262. #endif
  263.  
  264. I       neg     ax
  265. I       add     ax, Bias
  266. I       jmp     short done
  267.  
  268. special:
  269. I       or      dx, dx
  270. I       jz      nan
  271.  
  272. overflow:
  273. I       fld1
  274. I       mov     al, ExpoInf
  275. I       test    BYTE x[9], 80h
  276. I       jz      done
  277. I       fchs
  278. I       jmp     short done
  279.  
  280. nan:
  281. I       fldz
  282. I       mov     al, ExpoNan
  283. I       jmp     short done
  284.  
  285. underflow:
  286. zero:
  287. I       fldz
  288. I       mov     al, ExpoZero
  289.  
  290. done:
  291. I       fistp   LONG64 es:[si]
  292. I       mov     ah, 0
  293. I       mov     es:[si+8], ax
  294. I       fwait
  295. }
  296.  
  297. #if     DEBUG
  298. /* for debugging */
  299. long double pascal load64(long far *a)
  300. {
  301. I       les     bx, a
  302. I       fild    LONG64 es:[bx]
  303.         return;
  304. }
  305. #endif
  306.  
  307. /* from _mathl.h */
  308. typedef enum {
  309.         _Sine_,_CoSine_,_Tangent_,_ArcTan_,
  310.         _Log_,_Log2_, _Log10_,
  311.         _Exp_,_Exp2_, _Exp10_,_Power_
  312. } FLIB_functions;
  313.  
  314. #define FLIB_(fun)      _FAST_(0ECh + 2*fun)
  315. #define _FAST_(shortCode)       int     3Eh;  asm db    shortCode, 90h
  316.  
  317. #pragma warn -rvl
  318. long double pascal _FARFUNC __bcd_log10(bcd far *p)
  319. {
  320. I       les     bx, p
  321. I       fild    LONG64 es:[bx]
  322. asm     FLIB_   (_Log10_)
  323. I       sub     WORD es:[bx+8], Bias
  324. I       fiadd   WORD es:[bx+8]
  325. I       add     WORD es:[bx+8], Bias
  326. I       fwait
  327.         return;
  328. }
  329. #pragma warn .rvl
  330.  
  331. void pascal _FARFUNC __bcd_pow10(int n, bcd far *p)
  332. {
  333.         p->mantissa[0] = 1;
  334.         p->mantissa[1] = 0;
  335.         _AX = n;
  336. I       add     ax, Bias
  337. I       cmp     ax, 255
  338. I       jg      inf
  339. I       cmp     ax, 3
  340. I       jl      zero
  341.         p->expo = _AX;
  342.         return;
  343.  
  344. zero:
  345.         p->mantissa[0] = 0;
  346.         p->expo = 0;
  347.         return;
  348.  
  349. inf:
  350.         p->expo = ExpoInf;
  351.         return;
  352. }
  353.  
  354.