Raymond Toy pushed to branch issue-456-more-accurate-complex-div at cmucl / cmucl

Commits:

2 changed files:

Changes:

  • src/code/numbers.lisp
    ... ... @@ -596,6 +596,12 @@
    596 596
     ;; An implementation of Baudin and Smith's robust complex division for
    
    597 597
     ;; double-floats.  This is a pretty straightforward translation of the
    
    598 598
     ;; original in https://arxiv.org/pdf/1210.4539.
    
    599
    +;;
    
    600
    +;; This also includes improvements mentioned in
    
    601
    +;; https://lpc.events/event/11/contributions/1005/attachments/856/1625/Complex_divide.pdf.
    
    602
    +;; In particular iteration 1 and 3 are added.  Iteration 2 and 4 were
    
    603
    +;; not added.  The test examples from iteration 2 and 4 didn't change
    
    604
    +;; with or without changes added.
    
    599 605
     (let* (;; This is the value of Scilab's %eps variable.
    
    600 606
            (eps (scale-float 1d0 -52))
    
    601 607
            (rmin least-positive-normalized-double-float)
    

  • tests/float.lisp
    ... ... @@ -343,6 +343,9 @@
    343 343
         (assert-true (typep new-mode 'x86::float-modes))
    
    344 344
         (assert-equal new-mode (setf (x86::x87-floating-point-modes) new-mode))))
    
    345 345
     
    
    346
    +;; Rudimentary code to read C %a formatted numbers that look like
    
    347
    +;; "-0x1.c4dba4ba1ee79p-620".  We assume STRING is exactly in this
    
    348
    +;; format.  No error-checking is done.
    
    346 349
     (defun parse-%a (string)
    
    347 350
       (let* ((sign (if (char= (aref string 0) #\-)
    
    348 351
     		   -1
    
    ... ... @@ -358,9 +361,13 @@
    358 361
     			   1d0)
    
    359 362
     		    (- exp 52)))))
    
    360 363
     
    
    361
    -;; Tests for complex division.  From Baudin and Smith, and one test
    
    362
    -;; from Maxima.  Each test is a list of values: x, y, z-true,
    
    363
    -;; bits-of-accuracy, and max-ulp.
    
    364
    +;; Tests for complex division.  Tests 1-10 are from Baudin and Smith.
    
    365
    +;; Test 11 is an example from Maxima.  Test 12 is an example from the
    
    366
    +;; ansi-tests.  Tests 13-16 are for examples for improvement
    
    367
    +;; iterations 1-4 from McGehearty.
    
    368
    +;;
    
    369
    +;; Each test is a list of values: x, y, z-true (the value of x/y), and
    
    370
    +;; the bits of accuracy.
    
    364 371
     (defparameter *test-cases*
    
    365 372
       (list
    
    366 373
        ;; 1
    
    ... ... @@ -457,6 +464,10 @@
    457 464
     	 52 least-positive-double-float)
    
    458 465
        ))
    
    459 466
     
    
    467
    +;; Relative error in terms of bits of accuracy.  This is the
    
    468
    +;; definition used by Baudin and Smith.  A result of 53 means the two
    
    469
    +;; numbers have identical bits.  For complex numbers, we use the min
    
    470
    +;; of the bits of accuracy of the real and imaginary parts.
    
    460 471
     (defun rel-err (computed expected)
    
    461 472
       (flet ((rerr (c e)
    
    462 473
     	   (let ((diff (abs (- c e))))
    
    ... ... @@ -466,46 +477,6 @@
    466 477
         (min (rerr (realpart computed) (realpart expected))
    
    467 478
     	 (rerr (imagpart computed) (imagpart expected)))))
    
    468 479
     
    
    469
    -(defconstant +most-negative-normalized-float-exponent+
    
    470
    -  (nth-value 1 (decode-float least-positive-normalized-double-float)))
    
    471
    -
    
    472
    -(defun power-of-two-p (n)
    
    473
    -  (cond ((integerp n)
    
    474
    -	 (and (> n 0)
    
    475
    -	      (= 0 (logand (abs n) (+ (abs n) -1)))))
    
    476
    -	((floatp n)
    
    477
    -	 (and (> n 0.0)
    
    478
    -	      (= 0.5 (decode-float n))))))
    
    479
    -
    
    480
    -(defun ulp (f)
    
    481
    -  (cond
    
    482
    -    ((= f 0.0)
    
    483
    -     least-positive-double-float)
    
    484
    -    (t
    
    485
    -     (multiple-value-bind (significand expon)
    
    486
    -	 (decode-float f)
    
    487
    -       ;; If the exponent is smaller than the smallest
    
    488
    -       ;; normalized exponent, the ULP is the smallest float.
    
    489
    -       ;; Otherwise, the ULP has an exponent that is
    
    490
    -       ;; float-digits smaller, except when the fraction is a
    
    491
    -       ;; power of two, where we have to increase the exponent
    
    492
    -       ;; by 1.
    
    493
    -       (if (> expon +most-negative-normalized-float-exponent+)
    
    494
    -	   (scale-float 0.5d0
    
    495
    -			(- expon
    
    496
    -			   (float-digits f)
    
    497
    -			   (if (power-of-two-p significand)
    
    498
    -			       0
    
    499
    -			       -1)))
    
    500
    -	   least-positive-double-float)))))
    
    501
    -
    
    502
    -(defun complex-ulp (computed expected)
    
    503
    -  (flet ((real-ulp (f)
    
    504
    -	   (ulp (abs f))))
    
    505
    -    (let ((diff (- computed expected)))
    
    506
    -      (min (real-ulp (realpart diff))
    
    507
    -	   (real-ulp (imagpart diff))))))
    
    508
    -
    
    509 480
     (define-test complex-division.double
    
    510 481
       (:tag :issues)
    
    511 482
       (loop for k from 1
    
    ... ... @@ -515,14 +486,11 @@
    515 486
     	       test
    
    516 487
     	     (let* ((z (/ x y))
    
    517 488
     		    (diff (- z z-true))
    
    518
    -		    (rel (rel-err z z-true))
    
    519
    -		    (ulp (complex-ulp z z-true)))
    
    489
    +		    (rel (rel-err z z-true)))
    
    520 490
     	       
    
    521 491
     	       (assert-equal expected-rel
    
    522 492
     			     rel
    
    523
    -			     k x y z z-true diff rel)
    
    524
    -	       (assert-true (<= ulp max-ulp)
    
    525
    -			    k x y z z-true diff ulp max-ulp)))))
    
    493
    +			     k x y z z-true diff rel)))))
    
    526 494
     
    
    527 495
     (define-test complex-division.misc
    
    528 496
         (:tag :issue)