~ubuntu-branches/ubuntu/karmic/maxima/karmic

« back to all changes in this revision

Viewing changes to src/float.lisp

  • Committer: Bazaar Package Importer
  • Author(s): Barry deFreese
  • Date: 2006-07-06 17:04:52 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060706170452-j9ypoqc1kjfnz221
Tags: 5.9.3-1ubuntu1
* Re-sync with Debian
* Comment out backward-delete-char-untabify in maxima.el (Closes Malone #5273)
* debian/control: build-dep automake -> automake1.9 (Closes BTS: #374663)

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
;;;     (c) Copyright 1982 Massachusetts Institute of Technology         ;;;
9
9
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10
10
 
11
 
(in-package "MAXIMA")
 
11
(in-package :maxima)
12
12
 
13
13
(macsyma-module float)
14
14
 
192
192
  (cond ((equal (cadr l) 0)
193
193
         (if (not (equal (caddr l) 0))
194
194
             (mtell "Warning - an incorrect form for 0.0b0 has been generated."))
195
 
         (list '|0| '|.| '|0| 'b '|0|))
 
195
         (list '|0| '|.| '|0| '|b| '|0|))
196
196
        (t ;; L IS ALWAYS POSITIVE FP NUMBER
197
197
         (let ((extradigs (fix (add1 (quotient (haulong (caddr l)) 3.32))))
198
198
               (*m 1) (*cancelled 0)) 
234
234
                                                       (nreverse l3))))))
235
235
                                      (setq l2 (cons (car l1) l2) l1 (cdr l1))))))
236
236
                      (ncons '|0|))
237
 
                  (ncons 'b)
 
237
                  (ncons '|b|)
238
238
                  (explodec (sub1 (cadr l))))))))
239
239
 
240
240
(defun bigfloatp (x) 
550
550
                    ans (fpplus ans (fpquotient term (intofp n)))))))
551
551
     (return ans)))
552
552
 
553
 
(defun fpatan2 (y x)                    ; ATAN(Y/X) from -PI to PI
554
 
  (cond ((equal (car x) 0)              ; ATAN(INF), but what sign?
555
 
         (cond ((equal (car y) 0) (merror "atan(0//0) has been generated."))
 
553
;; atan(y/x) taking into account the quadrant.  (Also equal to
 
554
;; arg(x+%i*y).)
 
555
(defun fpatan2 (y x)
 
556
  (cond ((equal (car x) 0)
 
557
         ;; atan(y/0) = atan(inf), but what sign?
 
558
         (cond ((equal (car y) 0)
 
559
                (merror "atan(0//0) has been generated."))
556
560
               ((minusp (car y))
 
561
                ;; We're on the negative imaginary axis, so -pi/2.
557
562
                (fpquotient (fppi) (intofp -2)))
558
 
               (t (fpquotient (fppi) (intofp 2)))))
 
563
               (t
 
564
                ;; The positive imaginary axis, so +pi/2
 
565
                (fpquotient (fppi) (intofp 2)))))
559
566
        ((signp g (car x))
560
 
         (cond ((signp g (car y)) (fpatan (fpquotient y x)))
561
 
               (t (fpminus (fpatan (fpquotient y x))))))
 
567
         ;; x > 0.  atan(y/x) is the correct value.
 
568
         (fpatan (fpquotient y x)))
562
569
        ((signp g (car y))
 
570
         ;; x < 0, and y > 0.  We're in quadrant II, so the angle we
 
571
         ;; want is pi+atan(y/x).
563
572
         (fpplus (fppi) (fpatan (fpquotient y  x))))
564
 
        (t (fpdifference (fpatan (fpquotient y x)) (fppi))))) 
 
573
        (t
 
574
         ;; x <= 0 and y <= 0.  We're in quadrant III, so the angle we
 
575
         ;; want is atan(y/x)-pi.
 
576
         (fpdifference (fpatan (fpquotient y x)) (fppi))))) 
565
577
 
566
578
(defun tanbigfloat (a)
567
579
  (setq a (car a)) 
1026
1038
  (list (fpround (car a)) (plus -2 *m (cadr a))))
1027
1039
 
1028
1040
(defun timesbigfloat (h) 
1029
 
  (prog (fans tst r nfans) 
1030
 
     (setq fans (setq tst (bcons (fpone))) nfans 1)
 
1041
  (prog (fans r nfans) 
 
1042
     (setq fans (bcons (fpone)) nfans 1)
1031
1043
     (do ((l h (cdr l))) ((null l))
1032
1044
       (if (setq r (bigfloatp (car l)))
1033
1045
           (setq fans (bcons (fptimes* (cdr r) (cdr fans))))
1034
1046
           (setq nfans (list '(mtimes) (car l) nfans))))
1035
1047
     (return (cond ((equal nfans 1) fans)
1036
 
                   ((equal fans tst) nfans)
1037
1048
                   (t (simplify (list '(mtimes) fans nfans))))))) 
1038
1049
 
1039
1050
(defun invertbigfloat (a) 
1261
1272
     (return (cond ((null r) (list '(mabs) (car l)))
1262
1273
                   (t (bcons (fpabs (cdr r)))))))) 
1263
1274
 
 
1275
 
 
1276
;;;; Bigfloat implementations of special functions.
 
1277
;;;;
 
1278
 
 
1279
;;; This is still a bit messy.  Some functions here take bigfloat
 
1280
;;; numbers, represented by ((bigfloat) <mant> <exp>), but others want
 
1281
;;; just the FP number, represented by (<mant> <exp>).  Likewise, some
 
1282
;;; return a bigfloat, some return just the FP.
 
1283
;;;
 
1284
;;; This needs to be systemized somehow.  It isn't helped by the fact
 
1285
;;; that some of the routines above also do the samething.
 
1286
;;;
 
1287
;;; The implementation for the special functions for a complex
 
1288
;;; argument are mostly taken from W. Kahan, "Branch Cuts for Complex
 
1289
;;; Elementary Functions or Much Ado About Nothing's Sign Bit", in
 
1290
;;; Iserles and Powell (eds.) "The State of the Art in Numerical
 
1291
;;; Analysis", pp 165-211, Clarendon Press, 1987
 
1292
 
 
1293
;; Compute exp(x) - 1, but do it carefully to preserve precision when
 
1294
;; |x| is small.  X is a FP number, and a FP number is returned.  That
 
1295
;; is, no bigfloat stuff.
 
1296
(defun fpexpm1 (x)
 
1297
  ;; What is the right breakpoint here?  Is 1 ok?  Perhaps 1/e is better?
 
1298
  (cond ((fpgreaterp (fpabs x) (fpone))
 
1299
         ;; exp(x) - 1
 
1300
         (fpdifference (fpexp x) (fpone)))
 
1301
        (t
 
1302
         ;; Use Taylor series for exp(x) - 1
 
1303
         (let ((ans x)
 
1304
               (oans nil)
 
1305
               (term x))
 
1306
           (do ((n 2 (1+ n)))
 
1307
               ((equal ans oans))
 
1308
             (setf term (fpquotient (fptimes* x term) (intofp n)))
 
1309
             (setf oans ans)
 
1310
             (setf ans (fpplus ans term)))
 
1311
           ans))))
 
1312
  
 
1313
;; log(1+x) for small x.  X is FP number, and a FP number is returned.
 
1314
(defun fplog1p (x)
 
1315
  ;; Use the same series as given above for fplog.  For small x we use
 
1316
  ;; the series, otherwise fplog is accurate enough.
 
1317
  (cond ((fpgreaterp (fpabs x) (fpone))
 
1318
         (fplog (fpplus x (fpone))))
 
1319
        (t
 
1320
         (let* ((sum (intofp 0))
 
1321
                (term (fpquotient x (fpplus x (intofp 2))))
 
1322
                (f (fptimes* term term))
 
1323
                (oldans nil))
 
1324
           (do ((n 1 (+ n 2)))
 
1325
               ((equal sum oldans))
 
1326
             (setq oldans sum)
 
1327
             (setq sum (fpplus sum
 
1328
                               (fpquotient term (intofp n))))
 
1329
             (setq term (fptimes* term f)))
 
1330
           (fptimes* sum (intofp 2))))))
 
1331
 
 
1332
;; sinh(x) for real x.  X is a bigfloat, and a bigfloat is returned.
 
1333
(defun fpsinh (x)
 
1334
  ;; X must be a maxima bigfloat
 
1335
  
 
1336
  ;; See, for example, Hart et al., Computer Approximations, 6.2.27:
 
1337
  ;;
 
1338
  ;; sinh(x) = 1/2*(D(x) + D(x)/(1+D(x)))
 
1339
  ;;
 
1340
  ;; where D(x) = exp(x) - 1.
 
1341
  (let ((d (fpexpm1 (cdr (bigfloatp x)))))
 
1342
    (bcons
 
1343
     (fpquotient (fpplus d
 
1344
                         (fpquotient d
 
1345
                                     (fpplus d (fpone))))
 
1346
                 (intofp 2)))))
 
1347
 
 
1348
(defun big-float-sinh (x &optional y)
 
1349
  ;; The rectform for sinh for complex args should be numerically
 
1350
  ;; accurate, so return nil in that case.
 
1351
  (unless y
 
1352
    (fpsinh x)))
 
1353
 
 
1354
;; asinh(x) for real x.  X is a bigfloat, and a bigfloat is returned.
 
1355
(defun fpasinh (x)
 
1356
  ;; asinh(x) = sign(x) * log(|x| + sqrt(1+x*x))
 
1357
  ;;
 
1358
  ;; And
 
1359
  ;;
 
1360
  ;; asinh(x) = x, if 1+x*x = 1
 
1361
  ;;          = sign(x) * (log(2) + log(x)), large |x|
 
1362
  ;;          = sign(x) * log(2*|x| + 1/(|x|+sqrt(1+x*x))), if |x| > 2
 
1363
  ;;          = sign(x) * log1p(|x|+x^2/(1+sqrt(1+x*x))), otherwise.
 
1364
  ;;
 
1365
  ;; But I'm lazy right now and we only implement the last 2 cases.
 
1366
  ;; We should implement all cases.
 
1367
  (let* ((fp-x (cdr (bigfloatp x)))
 
1368
         (absx (fpabs fp-x))
 
1369
         (one (fpone))
 
1370
         (two (intofp 2))
 
1371
         (minus (minusp (car fp-x)))
 
1372
         result)
 
1373
    ;; We only use two formulas here.  |x| <= 2 and |x| > 2.  Should
 
1374
    ;; we add one for very big x and one for very small x, as given above.
 
1375
    (cond ((fpgreaterp absx two)
 
1376
           ;; |x| > 2
 
1377
           ;;
 
1378
           ;; log(2*|x| + 1/(|x|+sqrt(1+x^2)))
 
1379
           (setf result
 
1380
                 (fplog (fpplus (fptimes* absx two)
 
1381
                                (fpquotient one
 
1382
                                            (fpplus absx
 
1383
                                                    (fproot (bcons (fpplus one
 
1384
                                                                           (fptimes* absx absx)))
 
1385
                                                            2)))))))
 
1386
          (t
 
1387
           ;; |x| <= 2
 
1388
           ;;
 
1389
           ;; log1p(|x|+x^2/(1+sqrt(1+x^2)))
 
1390
           (let ((x*x (fptimes* absx absx)))
 
1391
             (setq result
 
1392
                   (fplog1p (fpplus absx
 
1393
                                    (fpquotient x*x
 
1394
                                                (fpplus one
 
1395
                                                        (fproot (bcons (fpplus one x*x))
 
1396
                                                                2)))))))))
 
1397
    (if minus
 
1398
        (bcons (fpminus result))
 
1399
        (bcons result))))
 
1400
 
 
1401
(defun complex-asinh (x y)
 
1402
  ;; asinh(z) = -%i * asin(%i*z)
 
1403
  (multiple-value-bind (u v)
 
1404
      (complex-asin (mul -1 y) x)
 
1405
    (values v (bcons (fpminus (cdr u))))))
 
1406
 
 
1407
(defun big-float-asinh (x &optional y)
 
1408
  (if y
 
1409
      (multiple-value-bind (u v)
 
1410
          (complex-asinh x y)
 
1411
        (add u
 
1412
             (mul '$%i v)))
 
1413
      (fpasinh x)))
 
1414
 
 
1415
(defun fpasin-core (x)
 
1416
  ;; asin(x) = atan(x/(sqrt(1-x^2))
 
1417
  ;;         = sgn(x)*[%pi/2 - atan(sqrt(1-x^2)/abs(x))]
 
1418
  ;;
 
1419
  ;; Use the first for  0 <= x < 1/2 and the latter for 1/2 < x <= 1.
 
1420
  ;;
 
1421
  ;; If |x| > 1, we need to do something else.
 
1422
  ;;
 
1423
  ;; asin(x) = -%i*log(sqrt(1-x^2)+%i*x)
 
1424
  ;;         = -%i*log(%i*x + %i*sqrt(x^2-1))
 
1425
  ;;         = -%i*[log(|x + sqrt(x^2-1)|) + %i*%pi/2]
 
1426
  ;;         = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
 
1427
  
 
1428
  (let ((fp-x (cdr (bigfloatp x))))
 
1429
    (cond ((minusp (car fp-x))
 
1430
           ;; asin(-x) = -asin(x);
 
1431
           (mul -1 (fpasin (bcons (fpminus fp-x)))))
 
1432
          ((fplessp fp-x (cdr bfhalf))
 
1433
           ;; 0 <= x < 1/2
 
1434
           ;; asin(x) = atan(x/sqrt(1-x^2))
 
1435
           (bcons
 
1436
            (fpatan (fpquotient fp-x
 
1437
                                (fproot (bcons
 
1438
                                         (fptimes* (fpdifference (fpone) fp-x)
 
1439
                                                   (fpplus (fpone) fp-x)))
 
1440
                                        2)))))
 
1441
          ((fpgreaterp fp-x (fpone))
 
1442
           ;; x > 1
 
1443
           ;; asin(x) = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
 
1444
           ;;
 
1445
           ;; Should we try to do something a little fancier with the
 
1446
           ;; argument to log and use log1p for better accuracy?
 
1447
           (let ((arg (fpplus fp-x
 
1448
                              (fproot (bcons (fptimes* (fpdifference fp-x (fpone))
 
1449
                                                       (fpplus fp-x (fpone))))
 
1450
                                      2))))
 
1451
             (add (div '$%pi 2)
 
1452
                  (mul -1 '$%i
 
1453
                       (bcons (fplog arg))))))
 
1454
                       
 
1455
          (t
 
1456
           ;; 1/2 <= x <= 1
 
1457
           ;; asin(x) = %pi/2 - atan(sqrt(1-x^2)/x)
 
1458
           (let ((piby2 (fpquotient (fppi) (intofp 2))))
 
1459
             (add (div '$%pi 2)
 
1460
                  (mul -1
 
1461
                       (bcons
 
1462
                        (fpatan
 
1463
                         (fpquotient (fproot
 
1464
                                      (bcons (fptimes* (fpdifference (fpone)
 
1465
                                                                     fp-x)
 
1466
                                                       (fpplus (fpone) fp-x)))
 
1467
                                      2)
 
1468
                                     fp-x))))))))))
 
1469
 
 
1470
;; asin(x) for real x.  X is a bigfloat, and a maxima number (real or
 
1471
;; complex) is returned.
 
1472
(defun fpasin (x)
 
1473
  ;; asin(x) = atan(x/(sqrt(1-x^2))
 
1474
  ;;         = sgn(x)*[%pi/2 - atan(sqrt(1-x^2)/abs(x))]
 
1475
  ;;
 
1476
  ;; Use the first for  0 <= x < 1/2 and the latter for 1/2 < x <= 1.
 
1477
  ;;
 
1478
  ;; If |x| > 1, we need to do something else.
 
1479
  ;;
 
1480
  ;; asin(x) = -%i*log(sqrt(1-x^2)+%i*x)
 
1481
  ;;         = -%i*log(%i*x + %i*sqrt(x^2-1))
 
1482
  ;;         = -%i*[log(|x + sqrt(x^2-1)|) + %i*%pi/2]
 
1483
  ;;         = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
 
1484
  
 
1485
  ($bfloat (fpasin-core x)))
 
1486
 
 
1487
;; Square root of a complex number (xx, yy).  Both are bigfloats.  FP
 
1488
;; (non-bigfloat) numbers are returned.
 
1489
(defun complex-sqrt (xx yy)
 
1490
  (let* ((x (cdr (bigfloatp xx)))
 
1491
         (y (cdr (bigfloatp yy)))
 
1492
         (rho (fpplus (fptimes* x x)
 
1493
                      (fptimes* y y))))
 
1494
    (setf rho (fpplus (fpabs x) (fproot (bcons rho) 2)))
 
1495
    (setf rho (fpplus rho rho))
 
1496
    (setf rho (fpquotient (fproot (bcons rho) 2) (intofp 2)))
 
1497
 
 
1498
    (let ((eta rho)
 
1499
          (nu y))
 
1500
      (when (fpgreaterp rho (intofp 0))
 
1501
        (setf nu (fpquotient (fpquotient nu rho) (intofp 2)))
 
1502
        (when (fplessp x (intofp 0))
 
1503
          (setf eta (fpabs nu))
 
1504
          (setf nu (if (minusp (car y))
 
1505
                       (fpminus rho)
 
1506
                       rho))))
 
1507
      (values eta nu))))
 
1508
 
 
1509
;; asin(z) for complex z = x + %i*y.  X and Y are bigfloats.  The real
 
1510
;; and imaginary parts are returned as bigfloat numbers.
 
1511
(defun complex-asin (x y)
 
1512
  (let ((x (cdr (bigfloatp x)))
 
1513
        (y (cdr (bigfloatp y))))
 
1514
    (multiple-value-bind (re-sqrt-1-z im-sqrt-1-z)
 
1515
        (complex-sqrt (bcons (fpdifference (intofp 1) x))
 
1516
                      (bcons (fpminus y)))
 
1517
      (multiple-value-bind (re-sqrt-1+z im-sqrt-1+z)
 
1518
          (complex-sqrt (bcons (fpplus (intofp 1) x))
 
1519
                        (bcons y))
 
1520
        ;; Realpart is atan(x/Re(sqrt(1-z)*sqrt(1+z)))
 
1521
        ;; Imagpart is asinh(Im(conj(sqrt(1-z))*sqrt(1+z)))
 
1522
        (values (bcons
 
1523
                 (fpatan (fpquotient x
 
1524
                                     (fpdifference (fptimes* re-sqrt-1-z
 
1525
                                                             re-sqrt-1+z)
 
1526
                                                   (fptimes* im-sqrt-1-z
 
1527
                                                             im-sqrt-1+z)))))
 
1528
                (fpasinh (bcons
 
1529
                          (fpdifference (fptimes* re-sqrt-1-z
 
1530
                                                  im-sqrt-1+z)
 
1531
                                        (fptimes* im-sqrt-1-z
 
1532
                                                  re-sqrt-1+z)))))))))
 
1533
  
 
1534
(defun big-float-asin (x &optional y)
 
1535
  (if y
 
1536
      (multiple-value-bind (u v)
 
1537
          (complex-asin x y)
 
1538
        (add u
 
1539
             (mul '$%i v)))
 
1540
      (fpasin x)))
 
1541
  
 
1542
  
 
1543
;; tanh(x) for real x.  X is a bigfloat, and a bigfloat is returned.
 
1544
(defun fptanh (x)
 
1545
  ;; X is Maxima bigfloat
 
1546
  ;; tanh(x) = D(2*x)/(2+D(2*x))
 
1547
  (let* ((two (intofp 2))
 
1548
         (fp (cdr (bigfloatp x)))
 
1549
         (d (fpexpm1 (fptimes* fp two))))
 
1550
    (bcons
 
1551
     (fpquotient d (fpplus d two)))))
 
1552
 
 
1553
;; tanh(z), z = x + %i*y.  X, Y are bigfloats, and a maxima number is
 
1554
;; returned.
 
1555
(defun complex-tanh (x y)
 
1556
  (let* ((fpx (cdr (bigfloatp x)))
 
1557
         (fpy (cdr (bigfloatp y)))
 
1558
         (tv (cdr (tanbigfloat (list y))))
 
1559
         (beta (fpplus (fpone) (fptimes* tv tv)))
 
1560
         (s (cdr (fpsinh x)))
 
1561
         (s^2 (fptimes* s s))
 
1562
         (rho (fproot (bcons (fpplus (fpone) s^2))
 
1563
                      2))
 
1564
         (den (fpplus (fpone) (fptimes* beta s^2))))
 
1565
    (values (bcons (fpquotient (fptimes* beta (fptimes* rho s))
 
1566
                               den))
 
1567
            (bcons (fpquotient tv den)))))
 
1568
 
 
1569
(defun big-float-tanh (x &optional y)
 
1570
  (if y
 
1571
      (multiple-value-bind (u v)
 
1572
          (complex-tanh x y)
 
1573
        (add u (mul '$%i v)))
 
1574
      (fptanh x)))
 
1575
 
 
1576
;; atanh(x) for real x, |x| <= 1.  X is a bigfloat, and a bigfloat is
 
1577
;; returned.
 
1578
(defun fpatanh (x)
 
1579
  ;; atanh(x) = -atanh(-x)
 
1580
  ;;          = 1/2*log1p(2*x/(1-x)), x >= 0.5
 
1581
  ;;          = 1/2*log1p(2*x+2*x*x/(1-x)), x <= 0.5
 
1582
 
 
1583
  (let* ((fp-x (cdr (bigfloatp x))))
 
1584
    (cond ((fplessp fp-x (intofp 0))
 
1585
           ;; atanh(x) = -atanh(-x)
 
1586
           (mul -1 (fpatanh (bcons (fpminus fp-x)))))
 
1587
          ((fpgreaterp fp-x (fpone))
 
1588
           ;; x > 1, so use complex version.
 
1589
           (multiple-value-bind (u v)
 
1590
               (complex-atanh x (bcons (intofp 0)))
 
1591
             (add u (mul '$%i v))))
 
1592
          ((fpgreaterp fp-x (cdr bfhalf))
 
1593
           ;; atanh(x) = 1/2*log1p(2*x/(1-x))
 
1594
           (bcons
 
1595
            (fptimes* bfhalf
 
1596
                      (fplog1p (fpquotient (fptimes* (intofp 2) fp-x)
 
1597
                                           (fpdifference (fpone) fp-x))))))
 
1598
          (t
 
1599
           ;; atanh(x) = 1/2*log1p(2*x + 2*x*x/(1-x))
 
1600
           (let ((2x (fptimes* (intofp 2) fp-x)))
 
1601
             (bcons
 
1602
              (fptimes* (cdr bfhalf)
 
1603
                        (fplog1p (fpplus 2x
 
1604
                                         (fpquotient (fptimes* 2x fp-x)
 
1605
                                                     (fpdifference (fpone) fp-x)))))))))))
 
1606
 
 
1607
;; Stuff which follows is derived from atanh z = (log(1 + z) - log(1 - z))/2
 
1608
;; which apparently originates with Kahan's "Much ado" paper.
 
1609
 
 
1610
;; The formulas for eta and nu below can be easily derived from
 
1611
;; rectform(atanh(x+%i*y)) =
 
1612
;;
 
1613
;; 1/4*log(((1+x)^2+y^2)/((1-x)^2+y^2)) + %i/2*(arg(1+x+%i*y)-arg(1-x+%i*(-y)))
 
1614
;;
 
1615
;; Expand the argument of log out and divide it out and we get
 
1616
;;
 
1617
;; log(((1+x)^2+y^2)/((1-x)^2+y^2)) = log(1+4*x/((1-x)^2+y^2))
 
1618
;;
 
1619
;; When y = 0, Im atanh z = 1/2 (arg(1 + x) - arg(1 - x))
 
1620
;;                        = if x < -1 then %pi/2 else if x > 1 then -%pi/2 else <whatever>
 
1621
;;
 
1622
;; Otherwise, arg(1 - x + %i*(-y)) = - arg(1 - x + %i*y),
 
1623
;; and Im atanh z = 1/2 (arg(1 + x + %i*y) + arg(1 - x + %i*y)).
 
1624
;; Since arg(x)+arg(y) = arg(x*y) (almost), we can simplify the
 
1625
;; imaginary part to
 
1626
;;
 
1627
;; arg((1+x+%i*y)*(1-x+%i*y)) = arg((1-x)*(1+x)-y^2+2*y*%i)
 
1628
;; = atan2(2*y,((1-x)*(1+x)-y^2))
 
1629
;;
 
1630
;; These are the eta and nu forms below.
 
1631
(defun complex-atanh (x y)
 
1632
  (let* ((fpx (cdr (bigfloatp x)))
 
1633
         (fpy (cdr (bigfloatp y)))
 
1634
         (beta (if (minusp (car fpx))
 
1635
                   (fpminus (fpone))
 
1636
                   (fpone)))
 
1637
     (x-lt-minus-1 (mevalp `((mlessp) ,x -1)))
 
1638
     (x-gt-plus-1 (mevalp `((mgreaterp) ,x 1)))
 
1639
     (y-equals-0 (like y '((bigfloat) 0 0)))
 
1640
         (x (fptimes* beta fpx))
 
1641
         (y (fptimes* beta (fpminus fpy)))
 
1642
         ;; Kahan has rho = 4/most-positive-float.  What should we do
 
1643
         ;; here about that?  Our big floats don't really have a
 
1644
         ;; most-positive float value.
 
1645
         (rho (intofp 0))
 
1646
         (t1 (fpplus (fpabs y) rho))
 
1647
         (t1^2 (fptimes* t1 t1))
 
1648
         (1-x (fpdifference (fpone) x))
 
1649
         ;; eta = log(1+4*x/((1-x)^2+y^2))/4
 
1650
         (eta (fpquotient
 
1651
               (fplog1p (fpquotient (fptimes* (intofp 4) x)
 
1652
                                    (fpplus (fptimes* 1-x 1-x)
 
1653
                                            t1^2)))
 
1654
               (intofp 4)))
 
1655
     ;; If y = 0, then Im atanh z = %pi/2 or -%pi/2.
 
1656
         ;; Otherwise nu = 1/2*atan2(2*y,(1-x)*(1+x)-y^2)
 
1657
         (nu (if y-equals-0
 
1658
           ;; EXTRA FPMINUS HERE TO COUNTERACT FPMINUS IN RETURN VALUE
 
1659
           (fpminus (if x-lt-minus-1 (cdr ($bfloat '((mquotient) $%pi 2))) (if x-gt-plus-1 (cdr ($bfloat '((mminus) ((mquotient) $%pi 2)))) (merror "COMPLEX-ATANH: HOW DID I GET HERE?"))))
 
1660
           (fptimes* (cdr bfhalf)
 
1661
                       (fpatan2
 
1662
                        (fptimes* (intofp 2) y)
 
1663
                        (fpdifference (fptimes* 1-x
 
1664
                                                (fpplus (fpone) x))
 
1665
                                      t1^2))))))
 
1666
    (values (bcons (fptimes* beta eta))
 
1667
        ;; WTF IS FPMINUS DOING HERE ??
 
1668
            (bcons (fpminus (fptimes* beta nu))))))
 
1669
    
 
1670
  
 
1671
(defun big-float-atanh (x &optional y)
 
1672
  (if y
 
1673
      (multiple-value-bind (u v)
 
1674
          (complex-atanh x y)
 
1675
        (add u (mul '$%i v)))
 
1676
      (fpatanh x)))
 
1677
 
 
1678
;; acos(x) for real x.  X is a bigfloat, and a maxima number is returned.
 
1679
(defun fpacos (x)
 
1680
  ;; acos(x) = %pi/2 - asin(x)
 
1681
  ($bfloat (add (div '$%pi 2)
 
1682
                (mul -1 (fpasin-core x)))))
 
1683
 
 
1684
(defun complex-acos (x y)
 
1685
  (let ((x (cdr (bigfloatp x)))
 
1686
        (y (cdr (bigfloatp y))))
 
1687
    (multiple-value-bind (re-sqrt-1-z im-sqrt-1-z)
 
1688
        (complex-sqrt (bcons (fpdifference (intofp 1) x))
 
1689
                      (bcons (fpminus y)))
 
1690
      (multiple-value-bind (re-sqrt-1+z im-sqrt-1+z)
 
1691
          (complex-sqrt (bcons (fpplus (intofp 1) x))
 
1692
                        (bcons y))
 
1693
        (values (bcons
 
1694
                 (fptimes* (intofp 2)
 
1695
                           (fpatan (fpquotient re-sqrt-1-z
 
1696
                                               re-sqrt-1+z))))
 
1697
                (fpasinh (bcons
 
1698
                          (fpdifference
 
1699
                           (fptimes* re-sqrt-1+z im-sqrt-1-z)
 
1700
                           (fptimes* im-sqrt-1+z re-sqrt-1-z)))))))))
 
1701
                                  
 
1702
 
 
1703
(defun big-float-acos (x &optional y)
 
1704
  (if y
 
1705
      (multiple-value-bind (u v)
 
1706
          (complex-acos x y)
 
1707
        (add u (mul '$%i v)))
 
1708
      (fpacos x)))
 
1709
 
 
1710
(defun complex-log (x y)
 
1711
  (let* ((x (cdr (bigfloatp x)))
 
1712
         (y (cdr (bigfloatp y)))
 
1713
         (t1 (let (($float2bf t))
 
1714
               ;; No warning message, please.
 
1715
               (floattofp 1.2d0)))
 
1716
         (t2 (intofp 3))
 
1717
         (rho (fpplus (fptimes* x x)
 
1718
                      (fptimes* y y)))
 
1719
         (abs-x (fpabs x))
 
1720
         (abs-y (fpabs y))
 
1721
         (beta (fpmax abs-x abs-y))
 
1722
         (theta (fpmin abs-x abs-y)))
 
1723
    (values (if (or (fpgreaterp t1 beta)
 
1724
                    (fplessp rho t2))
 
1725
                (fpquotient (fplog1p (fpplus (fptimes* (fpdifference beta (fpone))
 
1726
                                                       (fpplus beta (fpone)))
 
1727
                                             (fptimes* theta theta)))
 
1728
                            (intofp 2))
 
1729
                (fpquotient (fplog rho) (intofp 2)))
 
1730
            (fpatan2 y x))))
 
1731
 
 
1732
(defun big-float-log (x &optional y)
 
1733
  (if y
 
1734
      (multiple-value-bind (u v)
 
1735
          (complex-log x y)
 
1736
        (add (bcons u) (mul '$%i (bcons v))))
 
1737
      (let ((fp-x (cdr (bigfloatp x))))
 
1738
        (if (fplessp fp-x (intofp 0))
 
1739
            ;; ??? Do we want to return an exact %i*%pi or a float
 
1740
            ;; approximation?
 
1741
            (add (bcons (fplog (fpminus fp-x)))
 
1742
                 (mul '$%i (bcons (fppi))))
 
1743
            (bcons (fplog fp-x))))))
 
1744
 
 
1745
(defun big-float-sqrt (x &optional y)
 
1746
  (if y
 
1747
      (multiple-value-bind (u v)
 
1748
          (complex-sqrt x y)
 
1749
        (add (bcons u) (mul '$%i (bcons v))))
 
1750
      (let ((fp-x (cdr (bigfloatp x))))
 
1751
        (if (fplessp fp-x (intofp 0))
 
1752
            (mul '$%i (bcons (fproot (bcons (fpminus fp-x)) 2)))
 
1753
            (bcons (fproot x 2))))))
 
1754
 
1264
1755
(eval-when
1265
1756
    #+gcl (load)
1266
1757
    #-gcl (:load-toplevel)