Leaked source code of windows server 2003
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.

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