代码之家  ›  专栏  ›  技术社区  ›  f.lechleitner

计算Pi的Bellard算法

  •  2
  • f.lechleitner  · 技术社区  · 7 年前

    https://math.stackexchange.com/questions/1776840/confusion-with-bellards-algorithm-for-pi

    PROGRAM pi
    
    IMPLICIT NONE
    
    INTEGER :: find_number_of_primes, number_primes, last_digit, digit, N, &
    eps, i, j, multiplicity, test
    REAL :: log2, base, v_max, m, s, v, b, A, pi_sum
    INTEGER, ALLOCATABLE :: primes(:)   
    
    digit = 3
    eps = 2
    base = 10
    N = INT((digit+eps)*log2(base))
    pi_sum = 0
    
    number_primes = find_number_of_primes(2*N)
    ALLOCATE(primes(number_primes))
    CALL get_primes(number_primes, primes)
    
    DO i=1,SIZE(primes)
        v_max = INT(log(REAL(2*N))/log(REAL(primes(i))))
        m = primes(i)**v_max
        s = 0
        v = 0
        b = 1
        A = 1
        DO j = 1,(N)
            b = MOD((j/(primes(i)**multiplicity(digit, j)) * b), m)
            A = MOD((2*j-1)/(primes(i)**multiplicity(primes(i), (2*j-1)))*A, m)
            v = v - multiplicity(primes(i),j)+multiplicity(primes(i),(2*j-1))
            IF (v > 0) THEN
                s = MOD(s*j*b*(A**(-1))*a**(v_max-v), m)
            END IF
        END DO
        s = MOD(s * base**(digit-1), m)
        pi_sum = pi_sum + MOD((s/m), REAL(1))
    END DO
    
    PRINT*, pi_sum  
    
    END PROGRAM
    

    自定义函数 find_number_of_primes , get_primes , log2 multiplicity 正在按预期工作。第一个查找给定区间内的素数,第二个返回数组中的素数,第三个计算

    log_2(x) = log(x)/log(2) 
    

    最后一个通过检查第二个数除以第一个数的频率,直到除法的其余部分不再为零,来计算多重性(我猜这就是它的名字)。以下是源代码:

    对数:

    real function log2(x)
    implicit none
    real, intent(in) :: x
    
    log2 = log(x) / log(2.)
    end function
    

    integer function find_number_of_primes(limit) result(number_primes)
    implicit none
    INTEGER, INTENT(IN) :: limit
    INTEGER :: i, j
    LOGICAL :: is_prime
    
    number_primes = 0
    
    DO i = 3,(limit-1)
        is_prime = .TRUE.
        DO j = 2, (i-1)
            IF (MODULO(i, j) == 0) THEN
                is_prime = .FALSE.
                EXIT
            END IF
        END DO
        IF (is_prime .EQV. .TRUE.) THEN
        number_primes = number_primes + 1
        END IF
    END DO
    end function find_number_of_primes
    

    获取实际素数:

    SUBROUTINE get_primes(number_primes, primes)
    IMPLICIT NONE
    INTEGER, INTENT(IN) :: number_primes
    INTEGER :: i, found_primes, j
    LOGICAL:: is_prime
    INTEGER, INTENT(OUT) :: primes(number_primes)
    i = 3
    found_primes = 0
    DO
    is_prime = .TRUE.
    DO j = 2, (i-1)
        IF (MODULO(i,j) == 0) THEN
            is_prime = .FALSE.
        END IF
    END DO
    IF (is_prime .EQV. .TRUE.) THEN
        found_primes = found_primes + 1
        primes(found_primes) = i
        IF (found_primes == number_primes) EXIT
    END IF
    i = i + 1
    END DO
    
    
    end SUBROUTINE get_primes
    
    integer function multiplicity(a, b)
    implicit none
    INTEGER, INTENT(IN) :: a, b
    
    multiplicity = 0
    DO
        multiplicity = multiplicity + 1
        IF (MOD(b, (a**(multiplicity+1))) /= 0) THEN
            EXIT
        END IF
    END DO
    end function multiplicity
    

    整个文件的粘贴箱: https://pastebin.com/0F4zQYaH

    现在在我连接的问题中,在计算 在内环中有 a^{v(n,k)} a^{v(a,k)} . 此外,问题的内部循环从 1 1 2个 .

    NaN digit = 2 eps = 1

    ************ i =           1 ***************************
     v_max =   2.00000000
     m =   9.00000000
     ------------- j =           1 -------------------------------
     b =   0.00000000
     A =   0.00000000
     v =   0.00000000
     ------------- j =           2 -------------------------------
     b =   0.00000000
     A =   0.00000000
     v =   0.00000000
     ------------- j =           3 -------------------------------
     b =   0.00000000
     A =   0.00000000
     v =   0.00000000
     ------------- j =           4 -------------------------------
     b =   0.00000000
     A =   0.00000000
     v =   0.00000000
     ------------- j =           5 -------------------------------
     b =   0.00000000
     A =   0.00000000
     v =   1.00000000
     v > 0 --> s =              NaN
     ------------- j =           6 -------------------------------
     b =   0.00000000
     A =   0.00000000
     v =   1.00000000
     v > 0 --> s =              NaN
    

    一个完整的输出: https://pastebin.com/ucJNg6Vi

    有人能帮我找出我做错了什么吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Siong Thye Goh sara    7 年前

    您的代码中有一个错误:

    v = v - multiplicity(primes(i),j)+multiplicity(primes(i),(2*j-1))
    

    应该是

    v = v - multiplicity(primes(i),j)- multiplicity(primes(i),(2*j-1))
    

            s = MOD(s*j*b*(A**(-1))*a**(v_max-v), m)
    

    应该是

            s = MOD(s + j*b*(A**(-1))*a**(v_max-v), m)