Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Compensated summation #402

Open
Open
Labels
topic: algorithmssearching and sorting, merging, ...
@Beliavsky

Description

Rosetta Code has a section on Kahan summation, which "is a method of summing a series of numbers represented in a limited precision in a way that minimises the loss of precision in the result." I have extracted and slightly modified the sumc function from the code there. Here is an example of how it can produce a more accurate result than the intrinsic SUM. I suggest that compensated summation be added to stdlib.

module m
implicit none
private
public :: sumc,wp
integer, parameter :: wp = kind(1.0d0)
contains
function sumc(a) result(asum)	!add elements of the array, using limited precision.
real(kind=wp) , intent(in) :: a(:)
real(kind=wp) :: asum
real(kind=wp) :: s,c,y,t	! assistants.
integer 	 :: i ! stepper
integer :: n
n = size(a)
if (n < 1) then
 asum = 0.0_wp
 return
end if
s = a(1)	! start with the first element.
c = 0.0_wp	! no previous omissions to carry forward.
do i = 2,n	! step through the remainder of the array.
 y = a(i) - c		! combine the next value with the compensation.
 t = s + y		! augment the sum, temporarily in t.
 c = (t - s) - y	! catch what part of y didn't get added to t.
 s = t ! place the sum.
end do		 ! on to the next element.
asum = s	 ! c will no longer be zero.
end function sumc
end module m
program main
! 04/26/2021 11:39 AM driver for sumc
use m, only: sumc,wp
implicit none
integer, parameter :: n = 100000000
real(kind=wp) :: x(n)
real(kind=wp), parameter :: xadd = 10.0_wp**15
call random_seed()
call random_number(x)
x = x + xadd
print*,([sumc(x),sum(x)] - n*xadd)/n
end program main

output:
0.50331647999999996 2207252.1444556802

If you use wp = kind(1.0) (single precision) in the code above, you can see the difference even with xadd = 0.0. The output of

module m
implicit none
private
public :: sumc,wp
integer, parameter :: wp = kind(1.0)
contains
function sumc(a) result(asum)	!add elements of the array, using limited precision.
! adapted from Rosetta Code https://rosettacode.org/wiki/Kahan_summation
real(kind=wp) , intent(in) :: a(:)
real(kind=wp) :: asum
real(kind=wp) :: s,c,y,t	! assistants.
integer 	 :: i ! stepper
integer :: n
n = size(a)
if (n < 1) then
 asum = 0.0_wp
 return
end if
s = a(1)	! start with the first element.
c = 0.0_wp	! no previous omissions to carry forward.
do i = 2,n	! step through the remainder of the array.
 y = a(i) - c		! combine the next value with the compensation.
 t = s + y		! augment the sum, temporarily in t.
 c = (t - s) - y	! catch what part of y didn't get added to t.
 s = t ! place the sum.
end do		 ! on to the next element.
asum = s	 ! c will no longer be zero.
end function sumc
end module m
!
program main
! 04/26/2021 11:39 AM driver for sumc
use m, only: sumc,wp
implicit none
integer, parameter :: n = 100000000
real(kind=wp) :: x(n)
call random_seed()
call random_number(x)
print*,[sumc(x),sum(x)]/n
end program main

is
0.499940693 0.167772159

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: algorithmssearching and sorting, merging, ...

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /