Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1547 lines
39 KiB

  1. //---------------------------------------------------------------------------
  2. // Package Title ratpak
  3. // File conv.c
  4. // Author Timothy David Corrie Jr. ([email protected])
  5. // Copyright (C) 1995-97 Microsoft
  6. // Date 01-16-95
  7. //
  8. //
  9. // Description
  10. //
  11. // Contains conversion, input and output routines for numbers rationals
  12. // and longs.
  13. //
  14. //
  15. //
  16. //---------------------------------------------------------------------------
  17. #include <stdio.h>
  18. #include <tchar.h> // TCHAR version of sprintf
  19. #include <string.h>
  20. #include <malloc.h>
  21. #include <stdlib.h>
  22. #if defined( DOS )
  23. #include <dosstub.h>
  24. #else
  25. #include <windows.h>
  26. #endif
  27. #include <ratpak.h>
  28. BOOL fparserror=FALSE;
  29. BOOL gbinexact=FALSE;
  30. // digits 0..64 used by bases 2 .. 64
  31. TCHAR digits[65]=TEXT("0123456789")
  32. TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  33. TEXT("abcdefghijklmnopqrstuvwxyz_@");
  34. // ratio of internal 'digits' to output 'digits'
  35. // Calculated elsewhere as part of initialization and when base is changed
  36. long ratio; // int(log(2L^BASEXPWR)/log(nRadix))
  37. // Used to strip trailing zeroes, and prevent combinatorial explosions
  38. BOOL stripzeroesnum( PNUMBER pnum, long starting );
  39. // returns int(lognRadix(x)) quickly.
  40. long longlognRadix( long x );
  41. //----------------------------------------------------------------------------
  42. //
  43. // FUNCTION: fail
  44. //
  45. // ARGUMENTS: pointer to an error message.
  46. //
  47. // RETURN: None
  48. //
  49. // DESCRIPTION: fail dumps the error message then throws an exception
  50. //
  51. //----------------------------------------------------------------------------
  52. void fail( IN long errmsg )
  53. {
  54. #ifdef DEBUG
  55. fprintf( stderr, "%s\n", TEXT("Out of Memory") );
  56. #endif
  57. throw( CALC_E_OUTOFMEMORY );
  58. }
  59. //-----------------------------------------------------------------------------
  60. //
  61. // FUNCTION: _destroynum
  62. //
  63. // ARGUMENTS: pointer to a number
  64. //
  65. // RETURN: None
  66. //
  67. // DESCRIPTION: Deletes the number and associated allocation
  68. //
  69. //-----------------------------------------------------------------------------
  70. void _destroynum( IN PNUMBER pnum )
  71. {
  72. if ( pnum != NULL )
  73. {
  74. zfree( pnum );
  75. }
  76. }
  77. //-----------------------------------------------------------------------------
  78. //
  79. // FUNCTION: _destroyrat
  80. //
  81. // ARGUMENTS: pointer to a rational
  82. //
  83. // RETURN: None
  84. //
  85. // DESCRIPTION: Deletes the rational and associated
  86. // allocations.
  87. //
  88. //-----------------------------------------------------------------------------
  89. void _destroyrat( IN PRAT prat )
  90. {
  91. if ( prat != NULL )
  92. {
  93. destroynum( prat->pp );
  94. destroynum( prat->pq );
  95. zfree( prat );
  96. }
  97. }
  98. //-----------------------------------------------------------------------------
  99. //
  100. // FUNCTION: _createnum
  101. //
  102. // ARGUMENTS: size of number in 'digits'
  103. //
  104. // RETURN: pointer to a number
  105. //
  106. // DESCRIPTION: allocates and zeroes out number type.
  107. //
  108. //-----------------------------------------------------------------------------
  109. PNUMBER _createnum( IN long size )
  110. {
  111. PNUMBER pnumret=NULL;
  112. // sizeof( MANTTYPE ) is the size of a 'digit'
  113. pnumret = (PNUMBER)zmalloc( (int)(size+1) * sizeof( MANTTYPE ) +
  114. sizeof( NUMBER ) );
  115. if ( pnumret == NULL )
  116. {
  117. fail( CALC_E_OUTOFMEMORY );
  118. }
  119. return( pnumret );
  120. }
  121. //-----------------------------------------------------------------------------
  122. //
  123. // FUNCTION: _createrat
  124. //
  125. // ARGUMENTS: none
  126. //
  127. // RETURN: pointer to a rational
  128. //
  129. // DESCRIPTION: allocates a rational structure but does not
  130. // allocate the numbers that make up the rational p over q
  131. // form. These number pointers are left pointing to null.
  132. //
  133. //-----------------------------------------------------------------------------
  134. PRAT _createrat( void )
  135. {
  136. PRAT prat=NULL;
  137. prat = (PRAT)zmalloc( sizeof( RAT ) );
  138. if ( prat == NULL )
  139. {
  140. fail( CALC_E_OUTOFMEMORY );
  141. }
  142. prat->pp = NULL;
  143. prat->pq = NULL;
  144. return( prat );
  145. }
  146. //-----------------------------------------------------------------------------
  147. //
  148. // FUNCTION: numtorat
  149. //
  150. // ARGUMENTS: pointer to a number, nRadix number is in.
  151. //
  152. // RETURN: Rational representation of number.
  153. //
  154. // DESCRIPTION: The rational representation of the number
  155. // is guaranteed to be in the form p (number with internal
  156. // base representation) over q (number with internal base
  157. // representation) Where p and q are integers.
  158. //
  159. //-----------------------------------------------------------------------------
  160. PRAT numtorat( IN PNUMBER pin, IN unsigned long nRadix )
  161. {
  162. PRAT pout=NULL;
  163. PNUMBER pnRadixn=NULL;
  164. PNUMBER qnRadixn=NULL;
  165. DUPNUM( pnRadixn, pin );
  166. qnRadixn=longtonum( 1, nRadix );
  167. // Ensure p and q start out as integers.
  168. if ( pnRadixn->exp < 0 )
  169. {
  170. qnRadixn->exp -= pnRadixn->exp;
  171. pnRadixn->exp = 0;
  172. }
  173. createrat(pout);
  174. // There is probably a better way to do this.
  175. pout->pp = numtonRadixx( pnRadixn, nRadix, ratio );
  176. pout->pq = numtonRadixx( qnRadixn, nRadix, ratio );
  177. destroynum( pnRadixn );
  178. destroynum( qnRadixn );
  179. return( pout );
  180. }
  181. //----------------------------------------------------------------------------
  182. //
  183. // FUNCTION: nRadixxtonum
  184. //
  185. // ARGUMENTS: pointer to a number, base requested.
  186. //
  187. // RETURN: number representation in nRadix requested.
  188. //
  189. // DESCRIPTION: Does a base conversion on a number from
  190. // internal to requested base. Assumes number being passed
  191. // in is really in internal base form.
  192. //
  193. //----------------------------------------------------------------------------
  194. PNUMBER nRadixxtonum( IN PNUMBER a, IN unsigned long nRadix )
  195. {
  196. PNUMBER sum=NULL;
  197. PNUMBER powofnRadix=NULL;
  198. unsigned long bitmask;
  199. unsigned long cdigits;
  200. MANTTYPE *ptr;
  201. sum = longtonum( 0, nRadix );
  202. powofnRadix = longtonum( BASEX, nRadix );
  203. // A large penalty is paid for conversion of digits no one will see anyway.
  204. // limit the digits to the minimum of the existing precision or the
  205. // requested precision.
  206. cdigits = maxout + 1;
  207. if ( cdigits > (unsigned long)a->cdigit )
  208. {
  209. cdigits = (unsigned long)a->cdigit;
  210. }
  211. // scale by the internal base to the internal exponent offset of the LSD
  212. numpowlong( &powofnRadix, a->exp + (a->cdigit - cdigits), nRadix );
  213. // Loop over all the relative digits from MSD to LSD
  214. for ( ptr = &(MANT(a)[a->cdigit-1]); cdigits > 0 && !fhalt;
  215. ptr--, cdigits-- )
  216. {
  217. // Loop over all the bits from MSB to LSB
  218. for ( bitmask = BASEX/2; bitmask > 0; bitmask /= 2 )
  219. {
  220. addnum( &sum, sum, nRadix );
  221. if ( *ptr & bitmask )
  222. {
  223. sum->mant[0] |= 1;
  224. }
  225. }
  226. }
  227. // Scale answer by power of internal exponent.
  228. mulnum( &sum, powofnRadix, nRadix );
  229. destroynum( powofnRadix );
  230. sum->sign = a->sign;
  231. return( sum );
  232. }
  233. //-----------------------------------------------------------------------------
  234. //
  235. // FUNCTION: numtonRadixx
  236. //
  237. // ARGUMENTS: pointer to a number, nRadix of that number.
  238. // previously calculated ratio
  239. //
  240. // RETURN: number representation in internal nRadix.
  241. //
  242. // DESCRIPTION: Does a nRadix conversion on a number from
  243. // specified nRadix to requested nRadix. Assumes the nRadix
  244. // specified is the nRadix of the number passed in.
  245. //
  246. //-----------------------------------------------------------------------------
  247. PNUMBER numtonRadixx( IN PNUMBER a, IN unsigned long nRadix, IN long ratio )
  248. {
  249. PNUMBER pnumret = NULL; // pnumret is the number in internal form.
  250. PNUMBER thisdigit = NULL; // thisdigit holds the current digit of a
  251. // being summed into result.
  252. PNUMBER powofnRadix = NULL; // offset of external base exponent.
  253. MANTTYPE *ptrdigit; // pointer to digit being worked on.
  254. long idigit; // idigit is the iterate of digits in a.
  255. pnumret = longtonum( 0, BASEX );
  256. ptrdigit = MANT(a);
  257. // Digits are in reverse order, back over them LSD first.
  258. ptrdigit += a->cdigit-1;
  259. for ( idigit = 0; idigit < a->cdigit; idigit++ )
  260. {
  261. mulnumx( &pnumret, num_nRadix );
  262. // WARNING:
  263. // This should just smack in each digit into a 'special' thisdigit.
  264. // and not do the overhead of recreating the number type each time.
  265. thisdigit = longtonum( *ptrdigit--, BASEX );
  266. addnum( &pnumret, thisdigit, BASEX );
  267. destroynum( thisdigit );
  268. }
  269. DUPNUM( powofnRadix, num_nRadix );
  270. // Calculate the exponent of the external base for scaling.
  271. numpowlongx( &powofnRadix, a->exp );
  272. // ... and scale the result.
  273. mulnumx( &pnumret, powofnRadix );
  274. destroynum( powofnRadix );
  275. // And propagate the sign.
  276. pnumret->sign = a->sign;
  277. return( pnumret );
  278. }
  279. //-----------------------------------------------------------------------------
  280. //
  281. // FUNCTION: inrat
  282. //
  283. // ARGUMENTS:
  284. // fMantIsNeg true if mantissa is less than zero
  285. // pszMant a string representation of a number
  286. // fExpIsNeg true if exponent is less than zero
  287. // pszExp a string representation of a number
  288. //
  289. // RETURN: prat representation of string input.
  290. // Or NULL if no number scanned.
  291. //
  292. // EXPLANATION: This is for calc.
  293. //
  294. //
  295. //-----------------------------------------------------------------------------
  296. PRAT inrat( IN BOOL fMantIsNeg, IN LPTSTR pszMant, IN BOOL fExpIsNeg,
  297. IN LPTSTR pszExp )
  298. {
  299. PNUMBER pnummant=NULL; // holds mantissa in number form.
  300. PNUMBER pnumexp=NULL; // holds exponent in number form.
  301. PRAT pratexp=NULL; // holds exponent in rational form.
  302. PRAT prat=NULL; // holds exponent in rational form.
  303. long expt; // holds exponent
  304. // Deal with Mantissa
  305. if ( ( pszMant == NULL ) || ( *pszMant == TEXT('\0') ) )
  306. {
  307. // Preset value if no mantissa
  308. if ( ( pszExp == NULL ) || ( *pszExp == TEXT('\0') ) )
  309. {
  310. // Exponent not specified, preset value to zero
  311. DUPRAT(prat,rat_zero);
  312. }
  313. else
  314. {
  315. // Exponent specified, preset value to one
  316. DUPRAT(prat,rat_one);
  317. }
  318. }
  319. else
  320. {
  321. // Mantissa specified, convert to number form.
  322. pnummant = innum( pszMant );
  323. if ( pnummant == NULL )
  324. {
  325. return( NULL );
  326. }
  327. prat = numtorat( pnummant, nRadix );
  328. // convert to rational form, and cleanup.
  329. destroynum(pnummant);
  330. }
  331. if ( ( pszExp == NULL ) || ( *pszExp == TEXT('\0') ) )
  332. {
  333. // Exponent not specified, preset value to zero
  334. expt=0;
  335. }
  336. else
  337. {
  338. // Exponent specified, convert to number form.
  339. // Don't use native stuff, as it is restricted in the bases it can
  340. // handle.
  341. pnumexp = innum( pszExp );
  342. if ( pnumexp == NULL )
  343. {
  344. return( NULL );
  345. }
  346. // Convert exponent number form to native integral form, and cleanup.
  347. expt = numtolong( pnumexp, nRadix );
  348. destroynum( pnumexp );
  349. }
  350. // Convert native integral exponent form to rational multiplier form.
  351. pnumexp=longtonum( nRadix, BASEX );
  352. numpowlongx(&(pnumexp),abs(expt));
  353. createrat(pratexp);
  354. DUPNUM( pratexp->pp, pnumexp );
  355. pratexp->pq = longtonum( 1, BASEX );
  356. destroynum(pnumexp);
  357. if ( fExpIsNeg )
  358. {
  359. // multiplier is less than 1, this means divide.
  360. divrat( &prat, pratexp );
  361. }
  362. else
  363. {
  364. if ( expt > 0 )
  365. {
  366. // multiplier is greater than 1, this means divide.
  367. mulrat(&prat, pratexp);
  368. }
  369. // multiplier can be 1, in which case it'd be a waste of time to
  370. // multiply.
  371. }
  372. if ( fMantIsNeg )
  373. {
  374. // A negative number was used, adjust the sign.
  375. prat->pp->sign *= -1;
  376. }
  377. return( prat );
  378. }
  379. //-----------------------------------------------------------------------------
  380. //
  381. // FUNCTION: innum
  382. //
  383. // ARGUMENTS:
  384. // TCHAR *buffer
  385. //
  386. // RETURN: pnumber representation of string input.
  387. // Or NULL if no number scanned.
  388. //
  389. // EXPLANATION: This is a state machine,
  390. //
  391. // State Description Example, ^shows just read position.
  392. // which caused the transition
  393. //
  394. // START Start state ^1.0
  395. // MANTS Mantissa sign -^1.0
  396. // LZ Leading Zero 0^1.0
  397. // LZDP Post LZ dec. pt. 000.^1
  398. // LD Leading digit 1^.0
  399. // DZ Post LZDP Zero 000.0^1
  400. // DD Post Decimal digit .01^2
  401. // DDP Leading Digit dec. pt. 1.^2
  402. // EXPB Exponent Begins 1.0e^2
  403. // EXPS Exponent sign 1.0e+^5
  404. // EXPD Exponent digit 1.0e1^2 or even 1.0e0^1
  405. // EXPBZ Exponent begin post 0 0.000e^+1
  406. // EXPSZ Exponent sign post 0 0.000e+^1
  407. // EXPDZ Exponent digit post 0 0.000e+1^2
  408. // ERR Error case 0.0.^
  409. //
  410. // Terminal Description
  411. //
  412. // DP '.'
  413. // ZR '0'
  414. // NZ '1'..'9' 'A'..'Z' 'a'..'z' '@' '_'
  415. // SG '+' '-'
  416. // EX 'e' '^' e is used for nRadix 10, ^ for all other nRadixs.
  417. //
  418. //-----------------------------------------------------------------------------
  419. #define DP 0
  420. #define ZR 1
  421. #define NZ 2
  422. #define SG 3
  423. #define EX 4
  424. #define START 0
  425. #define MANTS 1
  426. #define LZ 2
  427. #define LZDP 3
  428. #define LD 4
  429. #define DZ 5
  430. #define DD 6
  431. #define DDP 7
  432. #define EXPB 8
  433. #define EXPS 9
  434. #define EXPD 10
  435. #define EXPBZ 11
  436. #define EXPSZ 12
  437. #define EXPDZ 13
  438. #define ERR 14
  439. #if defined( DEBUG )
  440. char *statestr[] = {
  441. "START",
  442. "MANTS",
  443. "LZ",
  444. "LZDP",
  445. "LD",
  446. "DZ",
  447. "DD",
  448. "DDP",
  449. "EXPB",
  450. "EXPS",
  451. "EXPD",
  452. "EXPBZ",
  453. "EXPSZ",
  454. "EXPDZ",
  455. "ERR",
  456. };
  457. #endif
  458. // New state is machine[state][terminal]
  459. char machine[ERR+1][EX+1]= {
  460. // DP, ZR, NZ, SG, EX
  461. // START
  462. { LZDP, LZ, LD, MANTS, ERR },
  463. // MANTS
  464. { LZDP, LZ, LD, ERR, ERR },
  465. // LZ
  466. { LZDP, LZ, LD, ERR, EXPBZ },
  467. // LZDP
  468. { ERR, DZ, DD, ERR, EXPB },
  469. // LD
  470. { DDP, LD, LD, ERR, EXPB },
  471. // DZ
  472. { ERR, DZ, DD, ERR, EXPBZ },
  473. // DD
  474. { ERR, DD, DD, ERR, EXPB },
  475. // DDP
  476. { ERR, DD, DD, ERR, EXPB },
  477. // EXPB
  478. { ERR, EXPD, EXPD, EXPS, ERR },
  479. // EXPS
  480. { ERR, EXPD, EXPD, ERR, ERR },
  481. // EXPD
  482. { ERR, EXPD, EXPD, ERR, ERR },
  483. // EXPBZ
  484. { ERR, EXPDZ, EXPDZ, EXPSZ, ERR },
  485. // EXPSZ
  486. { ERR, EXPDZ, EXPDZ, ERR, ERR },
  487. // EXPDZ
  488. { ERR, EXPDZ, EXPDZ, ERR, ERR },
  489. // ERR
  490. { ERR, ERR, ERR, ERR, ERR }
  491. };
  492. PNUMBER innum( IN TCHAR *buffer )
  493. {
  494. int c; // c is character being worked on currently.
  495. int state; // state is the state of the input state machine.
  496. long exps = 1L; // exps is exponent sign ( +/- 1 )
  497. long expt = 0L; // expt is exponent mantissa, should be unsigned
  498. long length = 0L; // length is the length of the input string.
  499. MANTTYPE *pmant; //
  500. PNUMBER pnumret=NULL; //
  501. length = _tcslen(buffer);
  502. createnum( pnumret, length );
  503. pnumret->sign = 1L;
  504. pnumret->cdigit = 0;
  505. pnumret->exp = 0;
  506. pmant = MANT(pnumret)+length-1;
  507. state = START;
  508. fparserror=FALSE; // clear global flag for parse error initially.
  509. while ( ( c = *buffer ) && c != TEXT('\n') )
  510. {
  511. int dp;
  512. dp = 0;
  513. // Added code to deal with international decimal point.
  514. while ( szDec[dp] && ( szDec[dp] == *buffer ) )
  515. {
  516. dp++;
  517. buffer++;
  518. }
  519. if ( dp )
  520. {
  521. if ( szDec[dp] == TEXT('\0') )
  522. {
  523. // OK pretend that was a decimal point for the state machine
  524. c = TEXT('.');
  525. buffer--;
  526. }
  527. else
  528. {
  529. // Backup that was no decimal point
  530. buffer -= (dp-1);
  531. c = *buffer++;
  532. }
  533. }
  534. switch ( c )
  535. {
  536. case TEXT('-'):
  537. case TEXT('+'):
  538. state=machine[state][SG];
  539. break;
  540. case TEXT('.'):
  541. state=machine[state][DP];
  542. break;
  543. case TEXT('0'):
  544. state=machine[state][ZR];
  545. break;
  546. case TEXT('^'):
  547. case TEXT('e'):
  548. if ( ( c == TEXT('^') ) || ( nRadix == 10 ) )
  549. {
  550. state=machine[state][EX];
  551. break;
  552. }
  553. // WARNING tricky dropthrough in the TEXT('e') as a digit case!!!
  554. default:
  555. state=machine[state][NZ];
  556. break;
  557. }
  558. switch ( state )
  559. {
  560. case MANTS:
  561. pnumret->sign = ( ( c == TEXT('-') ) ? -1 : 1);
  562. break;
  563. case EXPSZ:
  564. case EXPS:
  565. exps = ( ( c == TEXT('-') ) ? -1 : 1);
  566. break;
  567. case EXPDZ:
  568. case EXPD:
  569. {
  570. TCHAR *ptr; // offset into digit table.
  571. if ( ( nRadix <= 36 ) && ( nRadix > 10 ) )
  572. {
  573. c = toupper( c );
  574. }
  575. ptr = _tcschr( digits, (TCHAR)c );
  576. if ( ptr != NULL )
  577. {
  578. expt *= nRadix;
  579. expt += (long)(ptr - digits);
  580. }
  581. else
  582. {
  583. state=ERR;
  584. }
  585. }
  586. break;
  587. case LD:
  588. pnumret->exp++;
  589. case DD:
  590. {
  591. TCHAR *ptr; // offset into digit table.
  592. if ( ( nRadix <= 36 ) && ( nRadix > 10 ) )
  593. {
  594. // Allow upper and lower case letters as equivalent, base
  595. // is in the range where this is not ambiguous.
  596. c = toupper( c );
  597. }
  598. ptr = _tcschr( digits, (TCHAR)c );
  599. if ( ptr != NULL && ( (ptr - digits) < nRadix ) )
  600. {
  601. *pmant-- = (MANTTYPE)(ptr - digits);
  602. pnumret->exp--;
  603. pnumret->cdigit++;
  604. }
  605. else
  606. {
  607. state=ERR;
  608. // set global flag for parse error just in case anyone cares.
  609. fparserror=TRUE;
  610. }
  611. }
  612. break;
  613. case DZ:
  614. pnumret->exp--;
  615. break;
  616. case LZ:
  617. case LZDP:
  618. case DDP:
  619. break;
  620. }
  621. buffer++;
  622. }
  623. if ( state == DZ || state == EXPDZ )
  624. {
  625. pnumret->cdigit = 1;
  626. pnumret->exp=0;
  627. pnumret->sign=1;
  628. }
  629. else
  630. {
  631. while ( pnumret->cdigit < length )
  632. {
  633. pnumret->cdigit++;
  634. pnumret->exp--;
  635. }
  636. pnumret->exp += exps*expt;
  637. }
  638. if ( pnumret->cdigit == 0 )
  639. {
  640. destroynum( pnumret );
  641. pnumret = NULL;
  642. }
  643. stripzeroesnum( pnumret, maxout );
  644. return( pnumret );
  645. }
  646. //-----------------------------------------------------------------------------
  647. //
  648. // FUNCTION: longtorat
  649. //
  650. // ARGUMENTS: long
  651. //
  652. // RETURN: Rational representation of long input.
  653. //
  654. // DESCRIPTION: Converts long input to rational (p over q)
  655. // form, where q is 1 and p is the long.
  656. //
  657. //-----------------------------------------------------------------------------
  658. PRAT longtorat( IN long inlong )
  659. {
  660. PRAT pratret=NULL;
  661. createrat( pratret );
  662. pratret->pp = longtonum(inlong, BASEX );
  663. pratret->pq = longtonum(1L, BASEX );
  664. return( pratret );
  665. }
  666. //-----------------------------------------------------------------------------
  667. //
  668. // FUNCTION: realtorat
  669. //
  670. // ARGUMENTS: double real value.
  671. //
  672. // RETURN: Rational representation of the double
  673. //
  674. // DESCRIPTION: returns the rational (p over q)
  675. // representation of the double.
  676. //
  677. //-----------------------------------------------------------------------------
  678. PRAT realtorat( IN double real )
  679. {
  680. #if !defined( CLEVER )
  681. // get clever later, right now hack something to work
  682. TCHAR *ptr;
  683. PNUMBER pnum=NULL;
  684. PRAT prat=NULL;
  685. if ( ( ptr = (TCHAR*)zmalloc( 60 * sizeof(TCHAR) ) ) != NULL )
  686. {
  687. _stprintf( ptr, TEXT("%20.20le"), real );
  688. pnum=innum( ptr );
  689. prat = numtorat( pnum, nRadix );
  690. destroynum( pnum );
  691. zfree( ptr );
  692. return( prat );
  693. }
  694. else
  695. {
  696. return( NULL );
  697. }
  698. #else
  699. int i;
  700. union {
  701. double real;
  702. BYTE split[8];
  703. } unpack;
  704. long expt;
  705. long ratio;
  706. MANTTYPE *pmant;
  707. PNUMBER pnumret = NULL;
  708. PRAT pratret = NULL;
  709. createrat( pratret );
  710. if ( real == 0.0 )
  711. {
  712. pnumret=longtonum( 0L, 2L );
  713. }
  714. else
  715. {
  716. unpack.real=real;
  717. expt=unpack.split[7]*0x100+(unpack.split[6]>>4)-1023;
  718. createnum( pnumret, 52 );
  719. pmant = MANT(pnumret);
  720. for ( i = 63; i > 10; i-- )
  721. {
  722. *pmant++ = (MANTTYPE)((unpack.split[i/8]&(1<<(i%8)))!=0);
  723. }
  724. pnumret->exp=expt-52;
  725. pnumret->cdigit=52;
  726. }
  727. ratio = 1;
  728. while ( ratio > BASEX )
  729. {
  730. ratio *= 2;
  731. }
  732. pratret->pp = numtonRadixx( pnumret, 2, ratio );
  733. destroynum( pnumret );
  734. pratret->pq=longtonum( 1L, BASEX );
  735. if ( pratret->pp->exp < 0 )
  736. {
  737. pratret->pq->exp -= pratret->pp->exp;
  738. pratret->pp->exp = 0;
  739. }
  740. return( pratret );
  741. #endif
  742. }
  743. //-----------------------------------------------------------------------------
  744. //
  745. // FUNCTION: longtonum
  746. //
  747. // ARGUMENTS: long input and nRadix requested.
  748. //
  749. // RETURN: number
  750. //
  751. // DESCRIPTION: Returns a number representation in the
  752. // base requested of the long value passed in.
  753. //
  754. //-----------------------------------------------------------------------------
  755. PNUMBER longtonum( IN long inlong, IN unsigned long nRadix )
  756. {
  757. MANTTYPE *pmant;
  758. PNUMBER pnumret=NULL;
  759. createnum( pnumret, MAX_LONG_SIZE );
  760. pmant = MANT(pnumret);
  761. pnumret->cdigit = 0;
  762. pnumret->exp = 0;
  763. if ( inlong < 0 )
  764. {
  765. pnumret->sign = -1;
  766. inlong *= -1;
  767. }
  768. else
  769. {
  770. pnumret->sign = 1;
  771. }
  772. do {
  773. *pmant++ = (MANTTYPE)(inlong % nRadix);
  774. inlong /= nRadix;
  775. pnumret->cdigit++;
  776. } while ( inlong );
  777. return( pnumret );
  778. }
  779. //-----------------------------------------------------------------------------
  780. //
  781. // FUNCTION: rattolong
  782. //
  783. // ARGUMENTS: rational number in internal base.
  784. //
  785. // RETURN: long
  786. //
  787. // DESCRIPTION: returns the long representation of the
  788. // number input. Assumes that the number is in the internal
  789. // base.
  790. //
  791. //-----------------------------------------------------------------------------
  792. long rattolong( IN PRAT prat )
  793. {
  794. long lret;
  795. PRAT pint = NULL;
  796. if ( rat_gt( prat, rat_dword ) || rat_lt( prat, rat_min_long ) )
  797. {
  798. // Don't attempt rattolong of anything too big or small
  799. throw( CALC_E_DOMAIN );
  800. }
  801. DUPRAT(pint,prat);
  802. intrat( &pint );
  803. divnumx( &(pint->pp), pint->pq );
  804. DUPNUM( pint->pq, num_one );
  805. lret = numtolong( pint->pp, BASEX );
  806. destroyrat(pint);
  807. return( lret );
  808. }
  809. //-----------------------------------------------------------------------------
  810. //
  811. // FUNCTION: numtolong
  812. //
  813. // ARGUMENTS: number input and base of that number.
  814. //
  815. // RETURN: long
  816. //
  817. // DESCRIPTION: returns the long representation of the
  818. // number input. Assumes that the number is really in the
  819. // base claimed.
  820. //
  821. //-----------------------------------------------------------------------------
  822. long numtolong( IN PNUMBER pnum, IN unsigned long nRadix )
  823. {
  824. long lret;
  825. long expt;
  826. long length;
  827. MANTTYPE *pmant;
  828. lret = 0;
  829. pmant = MANT( pnum );
  830. pmant += pnum->cdigit - 1;
  831. expt = pnum->exp;
  832. length = pnum->cdigit;
  833. while ( length > 0 && length + expt > 0 )
  834. {
  835. lret *= nRadix;
  836. lret += *(pmant--);
  837. length--;
  838. }
  839. while ( expt-- > 0 )
  840. {
  841. lret *= (long)nRadix;
  842. }
  843. lret *= pnum->sign;
  844. return( lret );
  845. }
  846. //-----------------------------------------------------------------------------
  847. //
  848. // FUNCTION: BOOL stripzeroesnum
  849. //
  850. // ARGUMENTS: a number representation
  851. //
  852. // RETURN: TRUE if stripping done, modifies number in place.
  853. //
  854. // DESCRIPTION: Strips off trailing zeroes.
  855. //
  856. //-----------------------------------------------------------------------------
  857. BOOL stripzeroesnum( IN OUT PNUMBER pnum, long starting )
  858. {
  859. MANTTYPE *pmant;
  860. long cdigits;
  861. BOOL fstrip = FALSE;
  862. // point pmant to the LeastCalculatedDigit
  863. pmant=MANT(pnum);
  864. cdigits=pnum->cdigit;
  865. // point pmant to the LSD
  866. if ( cdigits > starting )
  867. {
  868. pmant += cdigits - starting;
  869. cdigits = starting;
  870. }
  871. // Check we haven't gone too far, and we are still looking at zeroes.
  872. while ( ( cdigits > 0 ) && !(*pmant) )
  873. {
  874. // move to next significant digit and keep track of digits we can
  875. // ignore later.
  876. pmant++;
  877. cdigits--;
  878. fstrip = TRUE;
  879. }
  880. // If there are zeroes to remove.
  881. if ( fstrip )
  882. {
  883. // Remove them.
  884. memcpy( MANT(pnum), pmant, (int)(cdigits*sizeof(MANTTYPE)) );
  885. // And adjust exponent and digit count accordingly.
  886. pnum->exp += ( pnum->cdigit - cdigits );
  887. pnum->cdigit = cdigits;
  888. }
  889. return( fstrip );
  890. }
  891. //-----------------------------------------------------------------------------
  892. //
  893. // FUNCTION: putnum
  894. //
  895. // ARGUMENTS: number representation
  896. // fmt, one of FMT_FLOAT FMT_SCIENTIFIC or
  897. // FMT_ENGINEERING
  898. //
  899. // RETURN: String representation of number.
  900. //
  901. // DESCRIPTION: Converts a number to it's string
  902. // representation. Returns a string that should be
  903. // zfree'd after use.
  904. //
  905. //-----------------------------------------------------------------------------
  906. TCHAR *putnum( IN PNUMBER *ppnum, IN int fmt )
  907. {
  908. TCHAR *psz;
  909. TCHAR *pret;
  910. long expt; // Actual number of digits to the left of decimal
  911. long eout; // Displayed exponent.
  912. long cexp; // the size of the exponent needed.
  913. long elen;
  914. long length;
  915. MANTTYPE *pmant;
  916. int fsciform=0; // If true scientific form is called for.
  917. PNUMBER pnum;
  918. PNUMBER round=NULL;
  919. long oldfmt = fmt;
  920. pnum=*ppnum;
  921. stripzeroesnum( pnum, maxout+2 );
  922. length = pnum->cdigit;
  923. expt = pnum->exp+length;
  924. if ( ( expt > maxout ) && ( fmt == FMT_FLOAT ) )
  925. {
  926. // Force scientific mode to prevent user from assuming 33rd digit is
  927. // exact.
  928. fmt = FMT_SCIENTIFIC;
  929. }
  930. // Make length small enough to fit in pret.
  931. if ( length > maxout )
  932. {
  933. length = maxout;
  934. }
  935. eout=expt-1;
  936. cexp = longlognRadix( expt );
  937. // 2 for signs, 1 for 'e'(or leading zero), 1 for dp, 1 for null and
  938. // 10 for maximum exponent size.
  939. pret = (TCHAR*)zmalloc( (maxout + 16) * sizeof(TCHAR) );
  940. psz = pret;
  941. if (!psz)
  942. {
  943. fail( CALC_E_OUTOFMEMORY );
  944. }
  945. // If there is a chance a round has to occour, round.
  946. if (
  947. // if number is zero no rounding.
  948. !zernum( pnum ) &&
  949. // if number of digits is less than the maximum output no rounding.
  950. pnum->cdigit >= maxout
  951. )
  952. {
  953. // Otherwise round.
  954. round=longtonum( nRadix, nRadix );
  955. divnum(&round, num_two, nRadix );
  956. // Make round number exponent one below the LSD for the number.
  957. round->exp = pnum->exp + pnum->cdigit - round->cdigit - maxout;
  958. round->sign = pnum->sign;
  959. }
  960. if ( fmt == FMT_FLOAT )
  961. {
  962. // cexp will now contain the size required by exponential.
  963. // Figure out if the exponent will fill more space than the nonexponent field.
  964. if ( ( length - expt > maxout + 2 ) || ( expt > maxout + 3 ) )
  965. {
  966. // Case where too many zeroes are to the right or left of the
  967. // decimal pt. And we are forced to switch to scientific form.
  968. fmt = FMT_SCIENTIFIC;
  969. }
  970. else
  971. {
  972. // Minimum loss of precision occours with listing leading zeros
  973. // if we need to make room for zeroes sacrifice some digits.
  974. if ( length + abs(expt) < maxout )
  975. {
  976. if ( round )
  977. {
  978. round->exp -= expt;
  979. }
  980. }
  981. }
  982. }
  983. if ( round != NULL )
  984. {
  985. BOOL fstrip=FALSE;
  986. long offset;
  987. addnum( ppnum, round, nRadix );
  988. pnum=*ppnum;
  989. offset=(pnum->cdigit+pnum->exp) - (round->cdigit+round->exp);
  990. fstrip = stripzeroesnum( pnum, offset );
  991. destroynum( round );
  992. if ( fstrip )
  993. {
  994. // WARNING: nesting/recursion, too much has been changed, need to
  995. // refigure format.
  996. return( putnum( &pnum, oldfmt ) );
  997. }
  998. }
  999. else
  1000. {
  1001. stripzeroesnum( pnum, maxout );
  1002. }
  1003. // Set up all the post rounding stuff.
  1004. pmant = MANT(pnum)+pnum->cdigit-1;
  1005. if (
  1006. // Case where too many digits are to the left of the decimal or
  1007. // FMT_SCIENTIFIC or FMT_ENGINEERING was specified.
  1008. ( fmt == FMT_SCIENTIFIC ) ||
  1009. ( fmt == FMT_ENGINEERING ) )
  1010. {
  1011. fsciform=1;
  1012. if ( eout != 0 )
  1013. {
  1014. if ( fmt == FMT_ENGINEERING )
  1015. {
  1016. expt = (eout % 3);
  1017. eout -= expt;
  1018. expt++;
  1019. // Fix the case where 0.02e-3 should really be 2.e-6 etc.
  1020. if ( expt < 0 )
  1021. {
  1022. expt += 3;
  1023. eout -= 3;
  1024. }
  1025. }
  1026. else
  1027. {
  1028. expt = 1;
  1029. }
  1030. }
  1031. }
  1032. else
  1033. {
  1034. fsciform=0;
  1035. eout=0;
  1036. }
  1037. // Make sure negative zeroes aren't allowed.
  1038. if ( ( pnum->sign == -1 ) && ( length > 0 ) )
  1039. {
  1040. *psz++ = TEXT('-');
  1041. }
  1042. if ( ( expt <= 0 ) && ( fsciform == 0 ) )
  1043. {
  1044. *psz++ = TEXT('0');
  1045. *psz++ = szDec[0];
  1046. // Used up a digit unaccounted for.
  1047. }
  1048. while ( expt < 0 )
  1049. {
  1050. *psz++ = TEXT('0');
  1051. expt++;
  1052. }
  1053. while ( length > 0 )
  1054. {
  1055. expt--;
  1056. *psz++ = digits[ *pmant-- ];
  1057. length--;
  1058. // Be more regular in using a decimal point.
  1059. if ( expt == 0 )
  1060. {
  1061. *psz++ = szDec[0];
  1062. }
  1063. }
  1064. while ( expt > 0 )
  1065. {
  1066. *psz++ = TEXT('0');
  1067. expt--;
  1068. // Be more regular in using a decimal point.
  1069. if ( expt == 0 )
  1070. {
  1071. *psz++ = szDec[0];
  1072. }
  1073. }
  1074. if ( fsciform )
  1075. {
  1076. if ( nRadix == 10 )
  1077. {
  1078. *psz++ = TEXT('e');
  1079. }
  1080. else
  1081. {
  1082. *psz++ = TEXT('^');
  1083. }
  1084. *psz++ = ( eout < 0 ? TEXT('-') : TEXT('+') );
  1085. eout = abs( eout );
  1086. elen=0;
  1087. do
  1088. {
  1089. // should this be eout % nRadix? or is that insane?
  1090. *psz++ = digits[ eout % nRadix ];
  1091. elen++;
  1092. eout /= nRadix;
  1093. } while ( eout > 0 );
  1094. *psz = TEXT('\0');
  1095. _tcsrev( &(psz[-elen]) );
  1096. }
  1097. *psz = TEXT('\0');
  1098. return( pret );
  1099. }
  1100. //-----------------------------------------------------------------------------
  1101. //
  1102. // FUNCTION: putrat
  1103. //
  1104. // ARGUMENTS:
  1105. // PRAT *representation of a number.
  1106. // long representation of base to dump to screen.
  1107. // fmt, one of FMT_FLOAT FMT_SCIENTIFIC or FMT_ENGINEERING
  1108. //
  1109. // RETURN: string
  1110. //
  1111. // DESCRIPTION: returns a string representation of rational number passed
  1112. // in, at least to the maxout digits. String returned should be zfree'd
  1113. // after use.
  1114. //
  1115. // NOTE: It may be that doing a GCD() could shorten the rational form
  1116. // And it may eventually be worthwhile to keep the result. That is
  1117. // why a pointer to the rational is passed in.
  1118. //
  1119. //-----------------------------------------------------------------------------
  1120. TCHAR *putrat( IN OUT PRAT *pa, IN unsigned long nRadix, IN int fmt )
  1121. {
  1122. TCHAR *psz;
  1123. PNUMBER p=NULL;
  1124. PNUMBER q=NULL;
  1125. long scaleby=0;
  1126. // Convert p and q of rational form from internal base to requested base.
  1127. // Scale by largest power of BASEX possible.
  1128. scaleby=min((*pa)->pp->exp,(*pa)->pq->exp);
  1129. if ( scaleby < 0 )
  1130. {
  1131. scaleby = 0;
  1132. }
  1133. (*pa)->pp->exp -= scaleby;
  1134. (*pa)->pq->exp -= scaleby;
  1135. p = nRadixxtonum( (*pa)->pp, nRadix );
  1136. q = nRadixxtonum( (*pa)->pq, nRadix );
  1137. // finally take the time hit to actually divide.
  1138. divnum( &p, q, nRadix );
  1139. psz = putnum( &p, fmt );
  1140. destroynum( p );
  1141. destroynum( q );
  1142. return( psz );
  1143. }
  1144. //-----------------------------------------------------------------------------
  1145. //
  1146. // FUNCTION: gcd
  1147. //
  1148. // ARGUMENTS:
  1149. // PNUMBER representation of a number.
  1150. // PNUMBER representation of a number.
  1151. //
  1152. // RETURN: Greatest common divisor in internal BASEX PNUMBER form.
  1153. //
  1154. // DESCRIPTION: gcd uses remainders to find the greatest common divisor.
  1155. //
  1156. // ASSUMPTIONS: gcd assumes inputs are integers.
  1157. //
  1158. // NOTE: Before GregSte and TimC proved the TRIM macro actually kept the
  1159. // size down cheaper than GCD, this routine was used extensively.
  1160. // now it is not used but might be later.
  1161. //
  1162. //-----------------------------------------------------------------------------
  1163. PNUMBER gcd( IN PNUMBER a, IN PNUMBER b )
  1164. {
  1165. PNUMBER r=NULL;
  1166. PNUMBER tmpa=NULL;
  1167. PNUMBER tmpb=NULL;
  1168. if ( lessnum( a, b ) )
  1169. {
  1170. DUPNUM(tmpa,b);
  1171. if ( zernum(a) )
  1172. {
  1173. return(tmpa);
  1174. }
  1175. DUPNUM(tmpb,a);
  1176. }
  1177. else
  1178. {
  1179. DUPNUM(tmpa,a);
  1180. if ( zernum(b) )
  1181. {
  1182. return(tmpa);
  1183. }
  1184. DUPNUM(tmpb,b);
  1185. }
  1186. remnum( &tmpa, tmpb, nRadix );
  1187. while ( !zernum( tmpa ) )
  1188. {
  1189. // swap tmpa and tmpb
  1190. r = tmpa;
  1191. tmpa = tmpb;
  1192. tmpb = r;
  1193. remnum( &tmpa, tmpb, nRadix );
  1194. }
  1195. destroynum( tmpa );
  1196. return( tmpb );
  1197. }
  1198. //-----------------------------------------------------------------------------
  1199. //
  1200. // FUNCTION: longfactnum
  1201. //
  1202. // ARGUMENTS:
  1203. // long integer to factorialize.
  1204. // long integer representing base of answer.
  1205. //
  1206. // RETURN: Factorial of input in nRadix PNUMBER form.
  1207. //
  1208. // NOTE: Not currently used.
  1209. //
  1210. //-----------------------------------------------------------------------------
  1211. PNUMBER longfactnum( IN long inlong, IN unsigned long nRadix )
  1212. {
  1213. PNUMBER lret=NULL;
  1214. PNUMBER tmp=NULL;
  1215. PNUMBER tmp1=NULL;
  1216. lret = longtonum( 1, nRadix );
  1217. while ( inlong > 0 )
  1218. {
  1219. tmp = longtonum( inlong--, nRadix );
  1220. mulnum( &lret, tmp, nRadix );
  1221. destroynum( tmp );
  1222. }
  1223. return( lret );
  1224. }
  1225. //-----------------------------------------------------------------------------
  1226. //
  1227. // FUNCTION: longprodnum
  1228. //
  1229. // ARGUMENTS:
  1230. // long integer to factorialize.
  1231. // long integer representing base of answer.
  1232. //
  1233. // RETURN: Factorial of input in base PNUMBER form.
  1234. //
  1235. //-----------------------------------------------------------------------------
  1236. PNUMBER longprodnum( IN long start, IN long stop, IN unsigned long nRadix )
  1237. {
  1238. PNUMBER lret=NULL;
  1239. PNUMBER tmp=NULL;
  1240. lret = longtonum( 1, nRadix );
  1241. while ( start <= stop )
  1242. {
  1243. if ( start )
  1244. {
  1245. tmp = longtonum( start, nRadix );
  1246. mulnum( &lret, tmp, nRadix );
  1247. destroynum( tmp );
  1248. }
  1249. start++;
  1250. }
  1251. return( lret );
  1252. }
  1253. //-----------------------------------------------------------------------------
  1254. //
  1255. // FUNCTION: numpowlong
  1256. //
  1257. // ARGUMENTS: root as number power as long and nRadix of
  1258. // number.
  1259. //
  1260. // RETURN: None root is changed.
  1261. //
  1262. // DESCRIPTION: changes numeric representation of root to
  1263. // root ** power. Assumes nRadix is the nRadix of root.
  1264. //
  1265. //-----------------------------------------------------------------------------
  1266. void numpowlong( IN OUT PNUMBER *proot, IN long power,
  1267. IN unsigned long nRadix )
  1268. {
  1269. PNUMBER lret=NULL;
  1270. lret = longtonum( 1, nRadix );
  1271. while ( power > 0 )
  1272. {
  1273. if ( power & 1 )
  1274. {
  1275. mulnum( &lret, *proot, nRadix );
  1276. }
  1277. mulnum( proot, *proot, nRadix );
  1278. TRIMNUM(*proot);
  1279. power >>= 1;
  1280. }
  1281. destroynum( *proot );
  1282. *proot=lret;
  1283. }
  1284. //-----------------------------------------------------------------------------
  1285. //
  1286. // FUNCTION: ratpowlong
  1287. //
  1288. // ARGUMENTS: root as rational, power as long.
  1289. //
  1290. // RETURN: None root is changed.
  1291. //
  1292. // DESCRIPTION: changes rational representation of root to
  1293. // root ** power.
  1294. //
  1295. //-----------------------------------------------------------------------------
  1296. void ratpowlong( IN OUT PRAT *proot, IN long power )
  1297. {
  1298. if ( power < 0 )
  1299. {
  1300. // Take the positive power and invert answer.
  1301. PNUMBER pnumtemp = NULL;
  1302. ratpowlong( proot, -power );
  1303. pnumtemp = (*proot)->pp;
  1304. (*proot)->pp = (*proot)->pq;
  1305. (*proot)->pq = pnumtemp;
  1306. }
  1307. else
  1308. {
  1309. PRAT lret=NULL;
  1310. lret = longtorat( 1 );
  1311. while ( power > 0 )
  1312. {
  1313. if ( power & 1 )
  1314. {
  1315. mulnumx( &(lret->pp), (*proot)->pp );
  1316. mulnumx( &(lret->pq), (*proot)->pq );
  1317. }
  1318. mulrat( proot, *proot );
  1319. trimit(&lret);
  1320. trimit(proot);
  1321. power >>= 1;
  1322. }
  1323. destroyrat( *proot );
  1324. *proot=lret;
  1325. }
  1326. }
  1327. //-----------------------------------------------------------------------------
  1328. //
  1329. // FUNCTION: longlog10
  1330. //
  1331. // ARGUMENTS: number as long.
  1332. //
  1333. // RETURN: returns int(log10(abs(number)+1)), useful in formatting output
  1334. //
  1335. //-----------------------------------------------------------------------------
  1336. long longlognRadix( long x )
  1337. {
  1338. long ret = 0;
  1339. x--;
  1340. if ( x < 0 )
  1341. {
  1342. x = -x;
  1343. }
  1344. while ( x )
  1345. {
  1346. ret++;
  1347. x /= nRadix;
  1348. }
  1349. return( ret );
  1350. }