0

I am overriding the concatenation operator to allow real values to be concatenated with strings.

function concatenateRealSigFigsWithString( floatIn, str ) result(cat)
    ! Arguments
    character( len=* ), intent(in)            :: str
    real(8),            intent(in)            :: floatIn(2)
    ! Returns
    character( len=: ), allocatable :: cat
    ! Variables
    logical :: remove_decimal = .False.
    real(8)             :: float
    character( len=16 ) :: float_as_str, fmt
    integer             :: sigfig, i

    float = floatIn(1)
    sigfig = int(floatIn(2))

    do i = sigfig, 1, -1
        if (float < 10.0_8**i .and. float > 10.0_8**(i-1) ) then
            fmt = '(F' // sigfig + 1 // '.' // sigfig - i // ')'
            if (i == sigfig) remove_decimal = .True.
        end if
    end do
    
    if ( float < 1 ) then
        fmt =  '(F' // sigfig + 2 // '.' // sigfig // ')'
    end if

    if (float < 0.1 ) then
        fmt = '(ES' // sigfig + 5 // '.' // sigfig - 1 // ')'
    end if

    if ( float > 10.0_8**sigfig ) then
        fmt = '(ES' // sigfig+6 // '.' // sigfig-1 // ')'
    end if


    write(float_as_str,fmt) float
    if (remove_decimal) float_as_str = float_as_str(1:len_trim(float_as_str)-1)

    cat = trim(float_as_str) // str
    ! cat = fmt

end function concatenateRealSigFigsWithString

The real value is a actually a list. The first element is the number and the second is the significant figures. Values between 0 and 10^(sigfig) are given in decimal form. Otherwise, the value is given in scientific form. The concatenation works for all values except those greater than 10^(sigfig). So the focus of the issue here is in the line fmt = '(ES' // sigfig+6 // '.' // sigfig-1 // ')'. For example, a value of 300,000 that should be written to 3 significant figures is formatted as 3.00E+0.

I can't figure out why the exponent is only showing one digit instead of 2, since it should be 3.00E+05.

I have tried specifying the width of exponent like fmt = '(ES' // sigfig+6 // '.' // sigfig-1 // 'E2)' but that just gives me 3.00E+00. I also tried expanding the width in case I did my math wrong and the exponent was getting cut off, but all that did was increase leading white space.

Any idea why the exponent is not showing the true value. Here is the code I used to test it.

program test

    interface operator(//)
        procedure :: concatenateRealSigFigsWithString, concatenateStringWithInteger
    end interface

    real(8) :: sigfig = 3

    print *, [2.337e-7_8, sigfig] // " slugs"
    print *, [2.337e-6_8, sigfig] // " slugs"
    print *, [2.337e-5_8, sigfig] // " slugs"
    print *, [2.337e-4_8, sigfig] // " slugs"
    print *, [2.337e-3_8, sigfig] // " slugs"
    print *, [2.337e-2_8, sigfig] // " slugs"
    print *, [2.337e-1_8, sigfig] // " slugs"
    print *, [2.337e0_8,  sigfig] // " slugs"
    print *, [2.337e01_8, sigfig] // " slugs"
    print *, [2.337e02_8, sigfig] // " slugs"
    print *, [2.337e03_8, sigfig] // " slugs"
    print *, [2.337e4_8,  sigfig] // " slugs"
    print *, [2.337e5_8,  sigfig] // " slugs"
    print *, [2.337e6_8,  sigfig] // " slugs"
    print *, [2.337e7_8,  sigfig] // " slugs"
    print *, [2.337e8_8,  sigfig] // " slugs"
    print *, [2.337e9_8,  sigfig] // " slugs"
    print *, [2.337e10_8, sigfig] // " slugs"

    
    contains

    function concatenateStringWithInteger(str,int) result(cat)
        ! Arguments
        character( len=* ), intent(in)  :: str
        integer,            intent(in)  :: int
        ! Returns
        character( len=: ), allocatable :: cat
        ! Variables
        character( len=9 )              :: int_as_str
    
        write(int_as_str,'(I0)') int
    
        cat = str // trim(int_as_str)
    
    end function concatenateStringWithInteger

    function concatenateRealSigFigsWithString( floatIn, str ) result(cat)
        ! Arguments
        character( len=* ), intent(in)            :: str
        real(8),            intent(in)            :: floatIn(2)
        ! Returns
        character( len=: ), allocatable :: cat
        ! Variables
        logical :: remove_decimal = .False.
        real(8)             :: float
        character( len=16 ) :: float_as_str, fmt
        integer             :: sigfig, i

        float = floatIn(1)
        sigfig = int(floatIn(2))

        do i = sigfig, 1, -1
            if (float < 10.0_8**i .and. float > 10.0_8**(i-1) ) then
                fmt = '(F' // sigfig + 1 // '.' // sigfig - i // ')'
                if (i == sigfig) remove_decimal = .True.
            end if
        end do
        
        if ( float < 1 ) then
            fmt =  '(F' // sigfig + 2 // '.' // sigfig // ')'
        end if

        if (float < 0.1 ) then
            fmt = '(ES' // sigfig + 5 // '.' // sigfig - 1 // ')'
        end if

        if ( float > 10.0_8**sigfig ) then
            fmt = '(ES' // sigfig+6 // '.' // sigfig-1 // ')'
        end if


        write(float_as_str,fmt) float
        if (remove_decimal) float_as_str = float_as_str(1:len_trim(float_as_str)-1)

        cat = trim(float_as_str) // str
        ! cat = fmt

    end function concatenateRealSigFigsWithString

end program test
nikost
  • 788
  • 6
  • 14
  • 1
    What is the value of `remove_decimal` when you get the undesired output? – francescalus Jan 10 '22 at 23:54
  • 1
    `logical :: remove_decimal = .False.` doesn't do what you think it does. See the linked question for what it does do. – francescalus Jan 11 '22 at 00:02
  • Thanks for the comment, I just found that variable to be the issue. It is true for all the cases I am getting the issue. I did verify that the if statement that triggers the value to go to .True. only occurs when the number of digits equals the number of significant figures. So that begs the question, what is causing this value to become .True.? @francescalus – nikost Jan 11 '22 at 00:03
  • I see you new comment now, that was the issue, thanks! @francescalus – nikost Jan 11 '22 at 00:05

0 Answers0