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

Commits:

2 changed files:

Changes:

  • src/code/numbers.lisp
    ... ... @@ -612,9 +612,14 @@
    612 612
     (defconstant +cdiv-be+ (/ 2 (* +cdiv-eps+ +cdiv-eps+)))
    
    613 613
     (defconstant +cdiv-2/eps+ (/ 2 +cdiv-eps+))
    
    614 614
     
    
    615
    +;; Make these functions accessible.  cdiv-double-float and
    
    616
    +;; cdiv-single-float are used by deftransforms.  Of course, two-arg-/
    
    617
    +;; is the interface to division.  cdiv-generic isn't used anywhere
    
    618
    +;; else.
    
    615 619
     (declaim (ext:start-block cdiv-double-float cdiv-single-float two-arg-/))
    
    616 620
     
    
    617 621
     (defun cdiv-double-float (x y)
    
    622
    +  "Accurate division of complex double-float numbers x and y."
    
    618 623
       (declare (type (complex double-float) x y)
    
    619 624
     	   (optimize (speed 3) (safety 0)))
    
    620 625
       (labels
    
    ... ... @@ -756,6 +761,7 @@
    756 761
     ;; Smith's algorithm for complex division for (complex single-float).
    
    757 762
     ;; We convert the parts to double-floats before computing the result.
    
    758 763
     (defun cdiv-single-float (x y)
    
    764
    +  "Accurate division of complex single-float numbers x and y."
    
    759 765
       (declare (type (complex single-float) x y))
    
    760 766
       (let ((a (float (realpart x) 1d0))
    
    761 767
     	(b (float (imagpart x) 1d0))
    
    ... ... @@ -776,6 +782,8 @@
    776 782
     
    
    777 783
     ;; Generic implementation of Smith's algorithm.
    
    778 784
     (defun cdiv-generic (x y)
    
    785
    +  "Complex division of generic numbers x and y.  One of x or y should be
    
    786
    +  a complex."
    
    779 787
       (let ((a (realpart x))
    
    780 788
     	(b (imagpart x))
    
    781 789
     	(c (realpart y))
    

  • tests/float.lisp
    ... ... @@ -369,122 +369,6 @@
    369 369
     			   1d0)
    
    370 370
     		    (- exp 52)))))
    
    371 371
     
    
    372
    -;; Tests for complex division.  Tests 1-10 are from Baudin and Smith.
    
    373
    -;; Test 11 is an example from Maxima.  Test 12 is an example from the
    
    374
    -;; ansi-tests.  Tests 13-16 are for examples for improvement
    
    375
    -;; iterations 1-4 from McGehearty.
    
    376
    -;;
    
    377
    -;; Each test is a list of values: x, y, z-true (the value of x/y), and
    
    378
    -;; the bits of accuracy.
    
    379
    -(defparameter *test-cases*
    
    380
    -  (list
    
    381
    -   ;; 1
    
    382
    -   (list (complex 1d0 1d0)
    
    383
    -	 (complex 1d0 (scale-float 1d0 1023))
    
    384
    -	 (complex (scale-float 1d0 -1023)
    
    385
    -		  (scale-float -1d0 -1023))
    
    386
    -	 53)
    
    387
    -   ;; 2
    
    388
    -   (list (complex 1d0 1d0)
    
    389
    -	 (complex (scale-float 1d0 -1023) (scale-float 1d0 -1023))
    
    390
    -	 (complex (scale-float 1d0 1023) 0)
    
    391
    -	 53)
    
    392
    -   ;; 3
    
    393
    -   (list (complex (scale-float 1d0 1023) (scale-float 1d0 -1023))
    
    394
    -	 (complex (scale-float 1d0 677) (scale-float 1d0 -677))
    
    395
    -	 (complex (scale-float 1d0 346) (scale-float -1d0 -1008))
    
    396
    -	 53)
    
    397
    -   ;; 4
    
    398
    -   (list (complex (scale-float 1d0 1023) (scale-float 1d0 1023))
    
    399
    -	 (complex 1d0 1d0)
    
    400
    -	 (complex (scale-float 1d0 1023) 0)
    
    401
    -	 53)
    
    402
    -   ;; 5
    
    403
    -   (list (complex (scale-float 1d0 1020) (scale-float 1d0 -844))
    
    404
    -	 (complex (scale-float 1d0 656) (scale-float 1d0 -780))
    
    405
    -	 (complex (scale-float 1d0 364) (scale-float -1d0 -1072))
    
    406
    -	 53)
    
    407
    -   ;; 6
    
    408
    -   (list (complex (scale-float 1d0 -71) (scale-float 1d0 1021))
    
    409
    -	 (complex (scale-float 1d0 1001) (scale-float 1d0 -323))
    
    410
    -	 (complex (scale-float 1d0 -1072) (scale-float 1d0 20))
    
    411
    -	 53)
    
    412
    -   ;; 7
    
    413
    -   (list (complex (scale-float 1d0 -347) (scale-float 1d0 -54))
    
    414
    -	 (complex (scale-float 1d0 -1037) (scale-float 1d0 -1058))
    
    415
    -	 (complex 3.898125604559113300d289 8.174961907852353577d295)
    
    416
    -	 53)
    
    417
    -   ;; 8
    
    418
    -   (list (complex (scale-float 1d0 -1074) (scale-float 1d0 -1074))
    
    419
    -	 (complex (scale-float 1d0 -1073) (scale-float 1d0 -1074))
    
    420
    -	 (complex 0.6d0 0.2d0)
    
    421
    -	 53)
    
    422
    -   ;; 9
    
    423
    -   (list (complex (scale-float 1d0 1015) (scale-float 1d0 -989))
    
    424
    -	 (complex (scale-float 1d0 1023) (scale-float 1d0 1023))
    
    425
    -	 (complex 0.001953125d0 -0.001953125d0)
    
    426
    -	 53)
    
    427
    -   ;; 10
    
    428
    -   (list (complex (scale-float 1d0 -622) (scale-float 1d0 -1071))
    
    429
    -	 (complex (scale-float 1d0 -343) (scale-float 1d0 -798))
    
    430
    -	 (complex 1.02951151789360578d-84 6.97145987515076231d-220)
    
    431
    -	 53)
    
    432
    -   ;; 11
    
    433
    -   ;; From Maxima
    
    434
    -   (list #c(5.43d-10 1.13d-100)
    
    435
    -	 #c(1.2d-311 5.7d-312)
    
    436
    -	 #c(3.691993880674614517999740937026568563794896024143749539711267954d301
    
    437
    -	    -1.753697093319947872394996242210428954266103103602859195409591583d301)
    
    438
    -	 52)
    
    439
    -   ;; 12
    
    440
    -   ;; Found by ansi tests. z/z should be exactly 1.
    
    441
    -   (list #c(1.565640716292489d19 0.0d0)
    
    442
    -	 #c(1.565640716292489d19 0.0d0)
    
    443
    -	 #c(1d0 0)
    
    444
    -	 53)
    
    445
    -   ;; 13
    
    446
    -   ;; Iteration 1.  Without this, we would instead return
    
    447
    -   ;;
    
    448
    -   ;;   (complex (parse-hex-float "0x1.ba8df8075bceep+155")
    
    449
    -   ;;            (parse-hex-float "-0x1.a4ad6329485f0p-895"))
    
    450
    -   ;;
    
    451
    -   ;; whose imaginary part is quite a bit off.
    
    452
    -   (list (complex (parse-hex-float "0x1.73a3dac1d2f1fp+509")
    
    453
    -		  (parse-hex-float "-0x1.c4dba4ba1ee79p-620"))
    
    454
    -	 (complex (parse-hex-float "0x1.adf526c249cf0p+353")
    
    455
    -		  (parse-hex-float "0x1.98b3fbc1677bbp-697"))
    
    456
    -	 (complex (parse-hex-float "0x1.BA8DF8075BCEEp+155")
    
    457
    -		  (parse-hex-float "-0x1.A4AD628DA5B74p-895"))
    
    458
    -	 53)
    
    459
    -   ;; 14
    
    460
    -   ;; Iteration 2.
    
    461
    -   (list (complex (parse-hex-float "-0x0.000000008e4f8p-1022")
    
    462
    -		  (parse-hex-float "0x0.0000060366ba7p-1022"))
    
    463
    -	 (complex (parse-hex-float "-0x1.605b467369526p-245")
    
    464
    -		  (parse-hex-float "0x1.417bd33105808p-256"))
    
    465
    -	 (complex (parse-hex-float "0x1.cde593daa4ffep-810")
    
    466
    -		  (parse-hex-float "-0x1.179b9a63df6d3p-799"))
    
    467
    -	 52)
    
    468
    -   ;; 15
    
    469
    -   ;; Iteration 3
    
    470
    -   (list (complex (parse-hex-float "0x1.cb27eece7c585p-355 ")
    
    471
    -		  (parse-hex-float "0x0.000000223b8a8p-1022"))
    
    472
    -	 (complex (parse-hex-float "-0x1.74e7ed2b9189fp-22")
    
    473
    -		  (parse-hex-float "0x1.3d80439e9a119p-731"))
    
    474
    -	 (complex (parse-hex-float "-0x1.3b35ed806ae5ap-333")
    
    475
    -		  (parse-hex-float "-0x0.05e01bcbfd9f6p-1022"))
    
    476
    -	 53)
    
    477
    -   ;; 16
    
    478
    -   ;; Iteration 4
    
    479
    -   (list (complex (parse-hex-float "-0x1.f5c75c69829f0p-530")
    
    480
    -		  (parse-hex-float "-0x1.e73b1fde6b909p+316"))
    
    481
    -	 (complex (parse-hex-float "-0x1.ff96c3957742bp+1023")
    
    482
    -		  (parse-hex-float "0x1.5bd78c9335899p+1021"))
    
    483
    -	 (complex (parse-hex-float "-0x1.423c6ce00c73bp-710")
    
    484
    -		  (parse-hex-float "0x1.d9edcf45bcb0ep-708"))
    
    485
    -	 52)
    
    486
    -   ))
    
    487
    -
    
    488 372
     ;; Relative error in terms of bits of accuracy.  This is the
    
    489 373
     ;; definition used by Baudin and Smith.  A result of 53 means the two
    
    490 374
     ;; numbers have identical bits.  For complex numbers, we use the min
    
    ... ... @@ -498,19 +382,148 @@
    498 382
         (min (rerr (realpart computed) (realpart expected))
    
    499 383
     	 (rerr (imagpart computed) (imagpart expected)))))
    
    500 384
     
    
    385
    +(defun do-cdiv-test (x y z-true expected-rel)
    
    386
    +  (let* ((z (/ x y))
    
    387
    +	 (rel (rel-err z z-true)))
    
    388
    +    (assert-equal expected-rel
    
    389
    +		  rel
    
    390
    +		  x y z z-true rel)))
    
    501 391
     ;; Issue #456: improve accuracy of division of complex double-floats.
    
    502
    -(define-test complex-division.double
    
    503
    -  (:tag :issues)
    
    504
    -  (loop for k from 1
    
    505
    -	for test in *test-cases*
    
    506
    -	do
    
    507
    -	   (destructuring-bind (x y z-true expected-rel)
    
    508
    -	       test
    
    509
    -	     (let* ((z (/ x y))
    
    510
    -		    (rel (rel-err z z-true)))
    
    511
    -	       (assert-equal expected-rel
    
    512
    -			     rel
    
    513
    -			     k x y z z-true diff rel)))))
    
    392
    +;;
    
    393
    +;; Tests for complex division.  Tests 1-10 are from Baudin and Smith.
    
    394
    +;; Test 11 is an example from Maxima.  Test 12 is an example from the
    
    395
    +;; ansi-tests where (/ z z) didn't produce exactly 1.  Tests 13-16 are
    
    396
    +;; for examples for improvement iterations 1-4 from McGehearty.
    
    397
    +(macrolet
    
    398
    +    ((frob (name x y z-true rel)
    
    399
    +       `(define-test ,name
    
    400
    +	  (:tag :issues)
    
    401
    +	  (do-cdiv-test ,x ,y ,z-true ,rel))))
    
    402
    +  ;; First cases are from Baudin and Smith
    
    403
    +  ;; 1
    
    404
    +  (frob cdiv.baudin-case.1
    
    405
    +	(complex 1d0 1d0)
    
    406
    +	(complex 1d0 (scale-float 1d0 1023))
    
    407
    +	(complex (scale-float 1d0 -1023)
    
    408
    +		 (scale-float -1d0 -1023))
    
    409
    +	53)
    
    410
    +  ;; 2
    
    411
    +  (frob cdiv.baudin-case.2
    
    412
    +	(complex 1d0 1d0)
    
    413
    +	(complex (scale-float 1d0 -1023) (scale-float 1d0 -1023))
    
    414
    +	(complex (scale-float 1d0 1023) 0)
    
    415
    +	53)
    
    416
    +  ;; 3
    
    417
    +  (frob cdiv.baudin-case.3
    
    418
    +	(complex (scale-float 1d0 1023) (scale-float 1d0 -1023))
    
    419
    +	(complex (scale-float 1d0 677) (scale-float 1d0 -677))
    
    420
    +	(complex (scale-float 1d0 346) (scale-float -1d0 -1008))
    
    421
    +	53)
    
    422
    +  ;; 4
    
    423
    +  (frob cdiv.baudin-case.4.overflow
    
    424
    +	(complex (scale-float 1d0 1023) (scale-float 1d0 1023))
    
    425
    +	(complex 1d0 1d0)
    
    426
    +	(complex (scale-float 1d0 1023) 0)
    
    427
    +	53)
    
    428
    +  ;; 5
    
    429
    +  (frob cdiv.baudin-case.5.underflow-ratio
    
    430
    +	(complex (scale-float 1d0 1020) (scale-float 1d0 -844))
    
    431
    +	(complex (scale-float 1d0 656) (scale-float 1d0 -780))
    
    432
    +	(complex (scale-float 1d0 364) (scale-float -1d0 -1072))
    
    433
    +	53)
    
    434
    +  ;; 6
    
    435
    +  (frob cdiv.baudin-case.6.underflow-realpart
    
    436
    +	(complex (scale-float 1d0 -71) (scale-float 1d0 1021))
    
    437
    +	(complex (scale-float 1d0 1001) (scale-float 1d0 -323))
    
    438
    +	(complex (scale-float 1d0 -1072) (scale-float 1d0 20))
    
    439
    +	53)
    
    440
    +  ;; 7
    
    441
    +  (frob cdiv.baudin-case.7.overflow-both-parts
    
    442
    +	(complex (scale-float 1d0 -347) (scale-float 1d0 -54))
    
    443
    +	(complex (scale-float 1d0 -1037) (scale-float 1d0 -1058))
    
    444
    +	(complex 3.898125604559113300d289 8.174961907852353577d295)
    
    445
    +	53)
    
    446
    +  ;; 8
    
    447
    +  (frob cdiv.baudin-case.8
    
    448
    +	(complex (scale-float 1d0 -1074) (scale-float 1d0 -1074))
    
    449
    +	(complex (scale-float 1d0 -1073) (scale-float 1d0 -1074))
    
    450
    +	(complex 0.6d0 0.2d0)
    
    451
    +	53)
    
    452
    +  ;; 9
    
    453
    +  (frob cdiv.baudin-case.9
    
    454
    +	(complex (scale-float 1d0 1015) (scale-float 1d0 -989))
    
    455
    +	(complex (scale-float 1d0 1023) (scale-float 1d0 1023))
    
    456
    +	(complex 0.001953125d0 -0.001953125d0)
    
    457
    +	53)
    
    458
    +  ;; 10
    
    459
    +  (frob cdiv.baudin-case.10.improve-imagpart-accuracy
    
    460
    +	(complex (scale-float 1d0 -622) (scale-float 1d0 -1071))
    
    461
    +	(complex (scale-float 1d0 -343) (scale-float 1d0 -798))
    
    462
    +	(complex 1.02951151789360578d-84 6.97145987515076231d-220)
    
    463
    +	53)
    
    464
    +  ;; 11
    
    465
    +  ;;
    
    466
    +  ;; From Maxima.  This was from a (private) email where Maxima used
    
    467
    +  ;; CL:/ to compute the ratio but was not very accurate.
    
    468
    +  (frob cdiv.maxima-case
    
    469
    +	#c(5.43d-10 1.13d-100)
    
    470
    +	#c(1.2d-311 5.7d-312)
    
    471
    +	#c(3.691993880674614517999740937026568563794896024143749539711267954d301
    
    472
    +	   -1.753697093319947872394996242210428954266103103602859195409591583d301)
    
    473
    +	52)
    
    474
    +  ;; 12
    
    475
    +  ;;
    
    476
    +  ;; Found by ansi tests. z/z should be exactly 1.
    
    477
    +  (frob cdiv.ansi-test-z/z
    
    478
    +	#c(1.565640716292489d19 0.0d0)
    
    479
    +	#c(1.565640716292489d19 0.0d0)
    
    480
    +	#c(1d0 0)
    
    481
    +	53)
    
    482
    +  ;; 13
    
    483
    +  ;; Iteration 1.  Without this, we would instead return
    
    484
    +  ;;
    
    485
    +  ;;   (complex (parse-hex-float "0x1.ba8df8075bceep+155")
    
    486
    +  ;;            (parse-hex-float "-0x1.a4ad6329485f0p-895"))
    
    487
    +  ;;
    
    488
    +  ;; whose imaginary part is quite a bit off.
    
    489
    +  (frob cdiv.mcgehearty-iteration.1
    
    490
    +	(complex (parse-hex-float "0x1.73a3dac1d2f1fp+509")
    
    491
    +		 (parse-hex-float "-0x1.c4dba4ba1ee79p-620"))
    
    492
    +	(complex (parse-hex-float "0x1.adf526c249cf0p+353")
    
    493
    +		 (parse-hex-float "0x1.98b3fbc1677bbp-697"))
    
    494
    +	(complex (parse-hex-float "0x1.BA8DF8075BCEEp+155")
    
    495
    +		 (parse-hex-float "-0x1.A4AD628DA5B74p-895"))
    
    496
    +	53)
    
    497
    +  ;; 14
    
    498
    +  ;; Iteration 2.
    
    499
    +  (frob cdiv.mcgehearty-iteration.2
    
    500
    +	(complex (parse-hex-float "-0x0.000000008e4f8p-1022")
    
    501
    +		 (parse-hex-float "0x0.0000060366ba7p-1022"))
    
    502
    +	(complex (parse-hex-float "-0x1.605b467369526p-245")
    
    503
    +		 (parse-hex-float "0x1.417bd33105808p-256"))
    
    504
    +	(complex (parse-hex-float "0x1.cde593daa4ffep-810")
    
    505
    +		 (parse-hex-float "-0x1.179b9a63df6d3p-799"))
    
    506
    +	52)
    
    507
    +  ;; 15
    
    508
    +  ;; Iteration 3
    
    509
    +  (frob cdiv.mcgehearty-iteration.3
    
    510
    +	(complex (parse-hex-float "0x1.cb27eece7c585p-355 ")
    
    511
    +		 (parse-hex-float "0x0.000000223b8a8p-1022"))
    
    512
    +	(complex (parse-hex-float "-0x1.74e7ed2b9189fp-22")
    
    513
    +		 (parse-hex-float "0x1.3d80439e9a119p-731"))
    
    514
    +	(complex (parse-hex-float "-0x1.3b35ed806ae5ap-333")
    
    515
    +		 (parse-hex-float "-0x0.05e01bcbfd9f6p-1022"))
    
    516
    +	53)
    
    517
    +  ;; 16
    
    518
    +  ;; Iteration 4
    
    519
    +  (frob cdiv.mcgehearty-iteration.4
    
    520
    +	(complex (parse-hex-float "-0x1.f5c75c69829f0p-530")
    
    521
    +		 (parse-hex-float "-0x1.e73b1fde6b909p+316"))
    
    522
    +	(complex (parse-hex-float "-0x1.ff96c3957742bp+1023")
    
    523
    +		 (parse-hex-float "0x1.5bd78c9335899p+1021"))
    
    524
    +	(complex (parse-hex-float "-0x1.423c6ce00c73bp-710")
    
    525
    +		 (parse-hex-float "0x1.d9edcf45bcb0ep-708"))
    
    526
    +	52))
    
    514 527
     
    
    515 528
     (define-test complex-division.misc
    
    516 529
         (:tag :issue)