Como esses valores de precisão dupla são precisos com 20 decimais?

Estou testando alguns erros de equivalência muito simples quando a precisão é um problema e esperava executar as operações com precisão dupla estendida (para que eu soubesse qual seria a resposta em ~ 19 dígitos) e, em seguida, execute as mesmas operações com precisão dupla (onde haveria erro de arredondamento no décimo sexto dígito), mas, de alguma forma, minha aritmética de dupla precisão está mantendo 19 dígitos de precisão.

Quando executo as operações em duplo estendido, depois codifico os números em outra rotina do Fortran, recebo os erros esperados, mas há algo estranho acontecendo quando atribuo uma variável de precisão dupla estendida a uma variável de precisão dupla aqui?

program code_gen
    implicit none 
    integer, parameter :: Edp = selected_real_kind(17)
    integer, parameter :: dp = selected_real_kind(8)
    real(kind=Edp) :: alpha10, x10, y10, z10 
    real(kind=dp) :: alpha8, x8, y8, z8

    real(kind = dp) :: pi_dp = 3.1415926535897932384626433832795028841971693993751058209749445

    integer :: iter
    integer :: niters = 10

    print*, 'tiny(x10) = ', tiny(x10)
    print*, 'tiny(x8)  = ', tiny(x8)
    print*, 'epsilon(x10) = ', epsilon(x10)
    print*, 'epsilon(x8)  = ', epsilon(x8)

    do iter = 1,niters
        x10 = rand()
        y10 = rand()
        z10 = rand()
        alpha10 = x10*(y10+z10)

        x8 = x10 
        x8 = x8 - pi_dp
        x8 = x8 + pi_dp
        y8 = y10 
        y8 = y8 - pi_dp
        y8 = y8 + pi_dp
        z8 = z10 
        z8 = z8 - pi_dp
        z8 = z8 + pi_dp
        alpha8 = alpha10

        write(*, '(a, es30.20)') 'alpha8 .... ', x8*(y8+z8)
        write(*, '(a, es30.20)') 'alpha10 ... ', alpha10

        if( alpha8 .gt. x8*(y8+z8) ) then
            write(*, '(a)') 'ERROR(.gt.)'
        elseif( alpha8 .lt. x8*(y8+z8) ) then
            write(*, '(a)') 'ERROR(.lt.)'
        endif
    enddo
end program code_gen

Onderand() é a função gfortran encontradaaqui.

Se falamos apenas de um tipo de precisão (por exemplo, duplo), podemos denotar a máquina epsilon comoE16 que é aproximadamente2.22E-16. Se fizermos uma simples adição de dois números reais,x+y, o número expresso da máquina resultante é(x+y)*(1+d1) Ondeabs(d1) < E16. Da mesma forma, se multiplicarmos esse número porz, o valor resultante é realmente(z*((x+y)*(1+d1))*(1+d2)) que é quase(z*(x+y)*(1+d1+d2)) Ondeabs(d1+d2) < 2*E16. Se passarmos agora para uma precisão dupla estendida, a única coisa que muda é queE16 vira paraE20 e tem um valor em torno de1.08E-19.

Minha esperança era realizar a análise com precisão dupla estendida para que eu pudesse comparar dois números quedevemos seja igual, mas mostre que, ocasionalmente, o erro de arredondamento fará com que as comparações falhem. Atribuindox8=x10, Eu esperava criar uma 'versão' de precisão dupla do valor estendido de precisão duplax10, onde apenas os primeiros ~ 16 dígitos dex8 conforme os valores dex10, mas, ao imprimir os valores, mostra que todos os 20 dígitos são iguais e que o erro de arredondamento de precisão dupla esperado não está ocorrendo como seria de esperar.

Note-se também que, antes dessa tentativa, eu escrevi um programa que realmente escreveoutro programa em que os valores dex, yez são 'codificados' com 20 casas decimais. Nesta versão do programa, as comparações de.gt. e.lt. falhou conforme o esperado, mas não consigo duplicar as mesmas falhas lançando um valor estendido de precisão dupla como uma variável de precisão dupla.

Em uma tentativa de "perturbar" ainda mais os valores de precisão dupla e adicionar um erro de arredondamento, adicionei e subtraímos,pi das minhas variáveis de precisão dupla, que devem deixar as variáveis restantes com algum erro de arredondamento de precisão dupla, mas ainda não estou vendo isso no resultado final.

questionAnswers(1)

yourAnswerToTheQuestion