¿Cómo son estos valores de doble precisión precisos a 20 decimales?

Estoy probando algunos errores de equivalencia muy simples cuando la precisión es un problema y esperaba realizar las operaciones en precisión doble extendida (para saber cuál sería la respuesta en ~ 19 dígitos) y luego realizar las mismas operaciones en precisión doble (donde habría un error de redondeo en el decimosexto dígito), pero de alguna manera mi aritmética de doble precisión mantiene 19 dígitos de precisión.

Cuando realizo las operaciones en doble extendido, luego codifico los números en otra rutina Fortran, obtengo los errores esperados, pero ¿ocurre algo extraño cuando asigno una variable de doble precisión extendida a una variable de doble precisión aquí?

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

dónderand() es la función gfortran encontradaaquí.

Si estamos hablando de un solo tipo de precisión (tome, por ejemplo, doble), entonces podemos denotar épsilon de máquina comoE16 que es aproximadamente2.22E-16. Si tomamos una simple suma de dos números reales,x+y, entonces el número expresado de la máquina resultante es(x+y)*(1+d1) dóndeabs(d1) < E16. Del mismo modo, si multiplicamos ese número porz, el valor resultante es realmente(z*((x+y)*(1+d1))*(1+d2)) que es casi(z*(x+y)*(1+d1+d2)) dóndeabs(d1+d2) < 2*E16. Si ahora pasamos a la precisión doble extendida, entonces lo único que cambia es queE16 recurre aE20 y tiene un valor de alrededor1.08E-19.

Mi esperanza era realizar el análisis en doble precisión extendida para poder comparar dos números quedebería sea igual pero demuestre que, en ocasiones, el error de redondeo hará que las comparaciones fallen. Asignandox8=x10, Esperaba crear una 'versión' de doble precisión del valor extendido de doble precisiónx10, donde solo los primeros ~ 16 dígitos dex8 ajustarse a los valores dex10, pero al imprimir los valores, muestra que los 20 dígitos son iguales y el error de redondeo de precisión doble esperado no se produce como era de esperar.

También se debe tener en cuenta que antes de este intento, escribí un programa que realmente escribeotro programa donde los valores dex, yyz están 'codificados' a 20 decimales. En esta versión del programa, las comparaciones de.gt. y.lt. falló como se esperaba, pero no puedo duplicar los mismos fallos al convertir un valor de doble precisión extendido como una variable de doble precisión.

En un intento de 'perturbar' aún más los valores de doble precisión y agregar un error de redondeo, agregué, luego resté,pi de mis variables de doble precisión que deberían dejar las variables restantes con algún error de redondeo de doble precisión, pero todavía no veo eso en el resultado final.

Respuestas a la pregunta(1)

Su respuesta a la pregunta