/ntl-5.5.2/src/xdouble.c

# · C · 1005 lines · 762 code · 239 blank · 4 comment · 215 complexity · 03868593e8b8176dc95f5bdc57a78376 MD5 · raw file

  1. #include <NTL/xdouble.h>
  2. #include <NTL/RR.h>
  3. #include <NTL/new.h>
  4. NTL_START_IMPL
  5. long xdouble::oprec = 10;
  6. void xdouble::SetOutputPrecision(long p)
  7. {
  8. if (p < 1) p = 1;
  9. if (NTL_OVERFLOW(p, 1, 0))
  10. Error("xdouble: output precision too big");
  11. oprec = p;
  12. }
  13. void xdouble::normalize()
  14. {
  15. if (x == 0)
  16. e = 0;
  17. else if (x > 0) {
  18. while (x < NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; }
  19. while (x > NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; }
  20. }
  21. else {
  22. while (x > -NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; }
  23. while (x < -NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; }
  24. }
  25. if (e >= NTL_OVFBND)
  26. Error("xdouble: overflow");
  27. if (e <= -NTL_OVFBND)
  28. Error("xdouble: underflow");
  29. }
  30. xdouble to_xdouble(double a)
  31. {
  32. if (a == 0 || a == 1 || (a > 0 && a >= NTL_XD_HBOUND_INV && a <= NTL_XD_HBOUND)
  33. || (a < 0 && a <= -NTL_XD_HBOUND_INV && a >= -NTL_XD_HBOUND)) {
  34. return xdouble(a, 0);
  35. }
  36. if (!IsFinite(&a))
  37. Error("double to xdouble conversion: non finite value");
  38. xdouble z = xdouble(a, 0);
  39. z.normalize();
  40. return z;
  41. }
  42. void conv(double& xx, const xdouble& a)
  43. {
  44. double x;
  45. long e;
  46. x = a.x;
  47. e = a.e;
  48. while (e > 0) { x *= NTL_XD_BOUND; e--; }
  49. while (e < 0) { x *= NTL_XD_BOUND_INV; e++; }
  50. xx = x;
  51. }
  52. xdouble operator+(const xdouble& a, const xdouble& b)
  53. {
  54. xdouble z;
  55. if (a.x == 0)
  56. return b;
  57. if (b.x == 0)
  58. return a;
  59. if (a.e == b.e) {
  60. z.x = a.x + b.x;
  61. z.e = a.e;
  62. z.normalize();
  63. return z;
  64. }
  65. else if (a.e > b.e) {
  66. if (a.e > b.e+1)
  67. return a;
  68. z.x = a.x + b.x*NTL_XD_BOUND_INV;
  69. z.e = a.e;
  70. z.normalize();
  71. return z;
  72. }
  73. else {
  74. if (b.e > a.e+1)
  75. return b;
  76. z.x = a.x*NTL_XD_BOUND_INV + b.x;
  77. z.e = b.e;
  78. z.normalize();
  79. return z;
  80. }
  81. }
  82. xdouble operator-(const xdouble& a, const xdouble& b)
  83. {
  84. xdouble z;
  85. if (a.x == 0)
  86. return -b;
  87. if (b.x == 0)
  88. return a;
  89. if (a.e == b.e) {
  90. z.x = a.x - b.x;
  91. z.e = a.e;
  92. z.normalize();
  93. return z;
  94. }
  95. else if (a.e > b.e) {
  96. if (a.e > b.e+1)
  97. return a;
  98. z.x = a.x - b.x*NTL_XD_BOUND_INV;
  99. z.e = a.e;
  100. z.normalize();
  101. return z;
  102. }
  103. else {
  104. if (b.e > a.e+1)
  105. return -b;
  106. z.x = a.x*NTL_XD_BOUND_INV - b.x;
  107. z.e = b.e;
  108. z.normalize();
  109. return z;
  110. }
  111. }
  112. xdouble operator-(const xdouble& a)
  113. {
  114. xdouble z;
  115. z.x = -a.x;
  116. z.e = a.e;
  117. return z;
  118. }
  119. xdouble operator*(const xdouble& a, const xdouble& b)
  120. {
  121. xdouble z;
  122. z.e = a.e + b.e;
  123. z.x = a.x * b.x;
  124. z.normalize();
  125. return z;
  126. }
  127. xdouble operator/(const xdouble& a, const xdouble& b)
  128. {
  129. xdouble z;
  130. if (b.x == 0) Error("xdouble division by 0");
  131. z.e = a.e - b.e;
  132. z.x = a.x / b.x;
  133. z.normalize();
  134. return z;
  135. }
  136. long compare(const xdouble& a, const xdouble& b)
  137. {
  138. xdouble z = a - b;
  139. if (z.x < 0)
  140. return -1;
  141. else if (z.x == 0)
  142. return 0;
  143. else
  144. return 1;
  145. }
  146. long sign(const xdouble& z)
  147. {
  148. if (z.x < 0)
  149. return -1;
  150. else if (z.x == 0)
  151. return 0;
  152. else
  153. return 1;
  154. }
  155. xdouble trunc(const xdouble& a)
  156. {
  157. if (a.x >= 0)
  158. return floor(a);
  159. else
  160. return ceil(a);
  161. }
  162. xdouble floor(const xdouble& aa)
  163. {
  164. xdouble z;
  165. xdouble a = aa;
  166. ForceToMem(&a.x);
  167. if (a.e == 0) {
  168. z.x = floor(a.x);
  169. z.e = 0;
  170. z.normalize();
  171. return z;
  172. }
  173. else if (a.e > 0) {
  174. return a;
  175. }
  176. else {
  177. if (a.x < 0)
  178. return to_xdouble(-1);
  179. else
  180. return to_xdouble(0);
  181. }
  182. }
  183. xdouble ceil(const xdouble& aa)
  184. {
  185. xdouble z;
  186. xdouble a = aa;
  187. ForceToMem(&a.x);
  188. if (a.e == 0) {
  189. z.x = ceil(a.x);
  190. z.e = 0;
  191. z.normalize();
  192. return z;
  193. }
  194. else if (a.e > 0) {
  195. return a;
  196. }
  197. else {
  198. if (a.x < 0)
  199. return to_xdouble(0);
  200. else
  201. return to_xdouble(1);
  202. }
  203. }
  204. xdouble to_xdouble(const ZZ& a)
  205. {
  206. long old_p = RR::precision();
  207. RR::SetPrecision(NTL_DOUBLE_PRECISION);
  208. static RR t;
  209. conv(t, a);
  210. double x;
  211. conv(x, t.mantissa());
  212. xdouble y, z, res;
  213. conv(y, x);
  214. power2(z, t.exponent());
  215. res = y*z;
  216. RR::SetPrecision(old_p);
  217. return res;
  218. }
  219. void conv(ZZ& x, const xdouble& a)
  220. {
  221. xdouble b = floor(a);
  222. long old_p = RR::precision();
  223. RR::SetPrecision(NTL_DOUBLE_PRECISION);
  224. static RR t;
  225. conv(t, b);
  226. conv(x, t);
  227. RR::SetPrecision(old_p);
  228. }
  229. xdouble fabs(const xdouble& a)
  230. {
  231. xdouble z;
  232. z.e = a.e;
  233. z.x = fabs(a.x);
  234. return z;
  235. }
  236. xdouble sqrt(const xdouble& a)
  237. {
  238. if (a == 0)
  239. return to_xdouble(0);
  240. if (a < 0)
  241. Error("xdouble: sqrt of negative number");
  242. xdouble t;
  243. if (a.e & 1) {
  244. t.e = (a.e - 1)/2;
  245. t.x = sqrt(a.x * NTL_XD_BOUND);
  246. }
  247. else {
  248. t.e = a.e/2;
  249. t.x = sqrt(a.x);
  250. }
  251. t.normalize();
  252. return t;
  253. }
  254. void power(xdouble& z, const xdouble& a, const ZZ& e)
  255. {
  256. xdouble b, res;
  257. b = a;
  258. res = 1;
  259. long n = NumBits(e);
  260. long i;
  261. for (i = n-1; i >= 0; i--) {
  262. res = res * res;
  263. if (bit(e, i))
  264. res = res * b;
  265. }
  266. if (sign(e) < 0)
  267. z = 1/res;
  268. else
  269. z = res;
  270. }
  271. void power(xdouble& z, const xdouble& a, long e)
  272. {
  273. static ZZ E;
  274. E = e;
  275. power(z, a, E);
  276. }
  277. void power2(xdouble& z, long e)
  278. {
  279. long hb = NTL_XD_HBOUND_LOG;
  280. long b = 2*hb;
  281. long q, r;
  282. q = e/b;
  283. r = e%b;
  284. while (r >= hb) {
  285. r -= b;
  286. q++;
  287. }
  288. while (r < -hb) {
  289. r += b;
  290. q--;
  291. }
  292. if (q >= NTL_OVFBND)
  293. Error("xdouble: overflow");
  294. if (q <= -NTL_OVFBND)
  295. Error("xdouble: underflow");
  296. double x = _ntl_ldexp(1.0, r);
  297. z.x = x;
  298. z.e = q;
  299. }
  300. void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c)
  301. // z = a + b*c
  302. {
  303. double x;
  304. long e;
  305. e = b.e + c.e;
  306. x = b.x * c.x;
  307. if (x == 0) {
  308. z = a;
  309. return;
  310. }
  311. if (a.x == 0) {
  312. z.e = e;
  313. z.x = x;
  314. z.normalize();
  315. return;
  316. }
  317. if (a.e == e) {
  318. z.x = a.x + x;
  319. z.e = e;
  320. z.normalize();
  321. return;
  322. }
  323. else if (a.e > e) {
  324. if (a.e > e+1) {
  325. z = a;
  326. return;
  327. }
  328. z.x = a.x + x*NTL_XD_BOUND_INV;
  329. z.e = a.e;
  330. z.normalize();
  331. return;
  332. }
  333. else {
  334. if (e > a.e+1) {
  335. z.x = x;
  336. z.e = e;
  337. z.normalize();
  338. return;
  339. }
  340. z.x = a.x*NTL_XD_BOUND_INV + x;
  341. z.e = e;
  342. z.normalize();
  343. return;
  344. }
  345. }
  346. void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c)
  347. // z = a - b*c
  348. {
  349. double x;
  350. long e;
  351. e = b.e + c.e;
  352. x = b.x * c.x;
  353. if (x == 0) {
  354. z = a;
  355. return;
  356. }
  357. if (a.x == 0) {
  358. z.e = e;
  359. z.x = -x;
  360. z.normalize();
  361. return;
  362. }
  363. if (a.e == e) {
  364. z.x = a.x - x;
  365. z.e = e;
  366. z.normalize();
  367. return;
  368. }
  369. else if (a.e > e) {
  370. if (a.e > e+1) {
  371. z = a;
  372. return;
  373. }
  374. z.x = a.x - x*NTL_XD_BOUND_INV;
  375. z.e = a.e;
  376. z.normalize();
  377. return;
  378. }
  379. else {
  380. if (e > a.e+1) {
  381. z.x = -x;
  382. z.e = e;
  383. z.normalize();
  384. return;
  385. }
  386. z.x = a.x*NTL_XD_BOUND_INV - x;
  387. z.e = e;
  388. z.normalize();
  389. return;
  390. }
  391. }
  392. double log(const xdouble& a)
  393. {
  394. static double LogBound = log(NTL_XD_BOUND);
  395. if (a.x <= 0) {
  396. Error("log(xdouble): argument must be positive");
  397. }
  398. return log(a.x) + a.e*LogBound;
  399. }
  400. xdouble xexp(double x)
  401. {
  402. const double LogBound = log(NTL_XD_BOUND);
  403. double y = x/LogBound;
  404. double iy = floor(y+0.5);
  405. if (iy >= NTL_OVFBND)
  406. Error("xdouble: overflow");
  407. if (iy <= -NTL_OVFBND)
  408. Error("xdouble: underflow");
  409. double fy = y - iy;
  410. xdouble res;
  411. res.e = long(iy);
  412. res.x = exp(fy*LogBound);
  413. res.normalize();
  414. return res;
  415. }
  416. /************** input / output routines **************/
  417. void ComputeLn2(RR&);
  418. void ComputeLn10(RR&);
  419. long ComputeMax10Power()
  420. {
  421. long old_p = RR::precision();
  422. RR::SetPrecision(NTL_BITS_PER_LONG);
  423. RR ln2, ln10;
  424. ComputeLn2(ln2);
  425. ComputeLn10(ln10);
  426. long k = to_long( to_RR(NTL_OVFBND/2) * ln2 / ln10 );
  427. RR::SetPrecision(old_p);
  428. return k;
  429. }
  430. xdouble PowerOf10(const ZZ& e)
  431. {
  432. static long init = 0;
  433. static xdouble v10k;
  434. static long k;
  435. if (!init) {
  436. long old_p = RR::precision();
  437. k = ComputeMax10Power();
  438. RR::SetPrecision(NTL_DOUBLE_PRECISION);
  439. v10k = to_xdouble(power(to_RR(10), k));
  440. RR::SetPrecision(old_p);
  441. init = 1;
  442. }
  443. ZZ e1;
  444. long neg;
  445. if (e < 0) {
  446. e1 = -e;
  447. neg = 1;
  448. }
  449. else {
  450. e1 = e;
  451. neg = 0;
  452. }
  453. long r;
  454. ZZ q;
  455. r = DivRem(q, e1, k);
  456. long old_p = RR::precision();
  457. RR::SetPrecision(NTL_DOUBLE_PRECISION);
  458. xdouble x1 = to_xdouble(power(to_RR(10), r));
  459. RR::SetPrecision(old_p);
  460. xdouble x2 = power(v10k, q);
  461. xdouble x3 = x1*x2;
  462. if (neg) x3 = 1/x3;
  463. return x3;
  464. }
  465. ostream& operator<<(ostream& s, const xdouble& a)
  466. {
  467. if (a == 0) {
  468. s << "0";
  469. return s;
  470. }
  471. long old_p = RR::precision();
  472. long temp_p = long(log(fabs(log(fabs(a))) + 1.0)/log(2.0)) + 10;
  473. RR::SetPrecision(temp_p);
  474. RR ln2, ln10, log_2_10;
  475. ComputeLn2(ln2);
  476. ComputeLn10(ln10);
  477. log_2_10 = ln10/ln2;
  478. ZZ log_10_a = to_ZZ(
  479. (to_RR(a.e)*to_RR(2*NTL_XD_HBOUND_LOG) + log(fabs(a.x))/log(2.0))/log_2_10);
  480. RR::SetPrecision(old_p);
  481. xdouble b;
  482. long neg;
  483. if (a < 0) {
  484. b = -a;
  485. neg = 1;
  486. }
  487. else {
  488. b = a;
  489. neg = 0;
  490. }
  491. ZZ k = xdouble::OutputPrecision() - log_10_a;
  492. xdouble c, d;
  493. c = PowerOf10(to_ZZ(xdouble::OutputPrecision()));
  494. d = PowerOf10(log_10_a);
  495. b = b / d;
  496. b = b * c;
  497. while (b < c) {
  498. b = b * 10.0;
  499. k++;
  500. }
  501. while (b >= c) {
  502. b = b / 10.0;
  503. k--;
  504. }
  505. b = b + 0.5;
  506. k = -k;
  507. ZZ B;
  508. conv(B, b);
  509. long bp_len = xdouble::OutputPrecision()+10;
  510. char *bp = NTL_NEW_OP char[bp_len];
  511. if (!bp) Error("xdouble output: out of memory");
  512. long len, i;
  513. len = 0;
  514. do {
  515. if (len >= bp_len) Error("xdouble output: buffer overflow");
  516. bp[len] = IntValToChar(DivRem(B, B, 10));
  517. len++;
  518. } while (B > 0);
  519. for (i = 0; i < len/2; i++) {
  520. char tmp;
  521. tmp = bp[i];
  522. bp[i] = bp[len-1-i];
  523. bp[len-1-i] = tmp;
  524. }
  525. i = len-1;
  526. while (bp[i] == '0') i--;
  527. k += (len-1-i);
  528. len = i+1;
  529. bp[len] = '\0';
  530. if (k > 3 || k < -len - 3) {
  531. // use scientific notation
  532. if (neg) s << "-";
  533. s << "0." << bp << "e" << (k + len);
  534. }
  535. else {
  536. long kk = to_long(k);
  537. if (kk >= 0) {
  538. if (neg) s << "-";
  539. s << bp;
  540. for (i = 0; i < kk; i++)
  541. s << "0";
  542. }
  543. else if (kk <= -len) {
  544. if (neg) s << "-";
  545. s << "0.";
  546. for (i = 0; i < -len-kk; i++)
  547. s << "0";
  548. s << bp;
  549. }
  550. else {
  551. if (neg) s << "-";
  552. for (i = 0; i < len+kk; i++)
  553. s << bp[i];
  554. s << ".";
  555. for (i = len+kk; i < len; i++)
  556. s << bp[i];
  557. }
  558. }
  559. delete [] bp;
  560. return s;
  561. }
  562. istream& operator>>(istream& s, xdouble& x)
  563. {
  564. long c;
  565. long cval;
  566. long sign;
  567. ZZ a, b;
  568. if (!s) Error("bad xdouble input");
  569. c = s.peek();
  570. while (IsWhiteSpace(c)) {
  571. s.get();
  572. c = s.peek();
  573. }
  574. if (c == '-') {
  575. sign = -1;
  576. s.get();
  577. c = s.peek();
  578. }
  579. else
  580. sign = 1;
  581. long got1 = 0;
  582. long got_dot = 0;
  583. long got2 = 0;
  584. a = 0;
  585. b = 1;
  586. cval = CharToIntVal(c);
  587. if (cval >= 0 && cval <= 9) {
  588. got1 = 1;
  589. while (cval >= 0 && cval <= 9) {
  590. mul(a, a, 10);
  591. add(a, a, cval);
  592. s.get();
  593. c = s.peek();
  594. cval = CharToIntVal(c);
  595. }
  596. }
  597. if (c == '.') {
  598. got_dot = 1;
  599. s.get();
  600. c = s.peek();
  601. cval = CharToIntVal(c);
  602. if (cval >= 0 && cval <= 9) {
  603. got2 = 1;
  604. while (cval >= 0 && cval <= 9) {
  605. mul(a, a, 10);
  606. add(a, a, cval);
  607. mul(b, b, 10);
  608. s.get();
  609. c = s.peek();
  610. cval = CharToIntVal(c);
  611. }
  612. }
  613. }
  614. if (got_dot && !got1 && !got2) Error("bad xdouble input");
  615. ZZ e;
  616. long got_e = 0;
  617. long e_sign;
  618. if (c == 'e' || c == 'E') {
  619. got_e = 1;
  620. s.get();
  621. c = s.peek();
  622. if (c == '-') {
  623. e_sign = -1;
  624. s.get();
  625. c = s.peek();
  626. }
  627. else if (c == '+') {
  628. e_sign = 1;
  629. s.get();
  630. c = s.peek();
  631. }
  632. else
  633. e_sign = 1;
  634. cval = CharToIntVal(c);
  635. if (cval < 0 || cval > 9) Error("bad xdouble input");
  636. e = 0;
  637. while (cval >= 0 && cval <= 9) {
  638. mul(e, e, 10);
  639. add(e, e, cval);
  640. s.get();
  641. c = s.peek();
  642. cval = CharToIntVal(c);
  643. }
  644. }
  645. if (!got1 && !got2 && !got_e) Error("bad xdouble input");
  646. xdouble t1, t2, v;
  647. if (got1 || got2) {
  648. conv(t1, a);
  649. conv(t2, b);
  650. v = t1/t2;
  651. }
  652. else
  653. v = 1;
  654. if (sign < 0)
  655. v = -v;
  656. if (got_e) {
  657. if (e_sign < 0) negate(e, e);
  658. t1 = PowerOf10(e);
  659. v = v * t1;
  660. }
  661. x = v;
  662. return s;
  663. }
  664. xdouble to_xdouble(const char *s)
  665. {
  666. long c;
  667. long cval;
  668. long sign;
  669. ZZ a, b;
  670. long i=0;
  671. if (!s) Error("bad xdouble input");
  672. c = s[i];
  673. while (IsWhiteSpace(c)) {
  674. i++;
  675. c = s[i];
  676. }
  677. if (c == '-') {
  678. sign = -1;
  679. i++;
  680. c = s[i];
  681. }
  682. else
  683. sign = 1;
  684. long got1 = 0;
  685. long got_dot = 0;
  686. long got2 = 0;
  687. a = 0;
  688. b = 1;
  689. cval = CharToIntVal(c);
  690. if (cval >= 0 && cval <= 9) {
  691. got1 = 1;
  692. while (cval >= 0 && cval <= 9) {
  693. mul(a, a, 10);
  694. add(a, a, cval);
  695. i++;
  696. c = s[i];
  697. cval = CharToIntVal(c);
  698. }
  699. }
  700. if (c == '.') {
  701. got_dot = 1;
  702. i++;
  703. c = s[i];
  704. cval = CharToIntVal(c);
  705. if (cval >= 0 && cval <= 9) {
  706. got2 = 1;
  707. while (cval >= 0 && cval <= 9) {
  708. mul(a, a, 10);
  709. add(a, a, cval);
  710. mul(b, b, 10);
  711. i++;
  712. c = s[i];
  713. cval = CharToIntVal(c);
  714. }
  715. }
  716. }
  717. if (got_dot && !got1 && !got2) Error("bad xdouble input");
  718. ZZ e;
  719. long got_e = 0;
  720. long e_sign;
  721. if (c == 'e' || c == 'E') {
  722. got_e = 1;
  723. i++;
  724. c = s[i];
  725. if (c == '-') {
  726. e_sign = -1;
  727. i++;
  728. c = s[i];
  729. }
  730. else if (c == '+') {
  731. e_sign = 1;
  732. i++;
  733. c = s[i];
  734. }
  735. else
  736. e_sign = 1;
  737. cval = CharToIntVal(c);
  738. if (cval < 0 || cval > 9) Error("bad xdouble input");
  739. e = 0;
  740. while (cval >= 0 && cval <= 9) {
  741. mul(e, e, 10);
  742. add(e, e, cval);
  743. i++;
  744. c = s[i];
  745. cval = CharToIntVal(c);
  746. }
  747. }
  748. if (!got1 && !got2 && !got_e) Error("bad xdouble input");
  749. xdouble t1, t2, v;
  750. if (got1 || got2) {
  751. conv(t1, a);
  752. conv(t2, b);
  753. v = t1/t2;
  754. }
  755. else
  756. v = 1;
  757. if (sign < 0)
  758. v = -v;
  759. if (got_e) {
  760. if (e_sign < 0) negate(e, e);
  761. t1 = PowerOf10(e);
  762. v = v * t1;
  763. }
  764. return v;
  765. }
  766. NTL_END_IMPL