Silverfrost Forums

Welcome to our forums

Converting REAL number to character string in FTN95?

2 Sep 2010 4:38 #6881

I've used CNUM several times to convert an integer value such as 517, to a character string containing a 5, a 1, and a 7.

Is there a similar function that can convert a real number such as 3.14 to a character string containing a 3, a period, a 1, and a 4?

And, are there functions that can go the other way? Converting a character string to an integer, or to a real number?

Thank you!

2 Sep 2010 8:08 #6886

Quoted from brucebowler Look at 'internal writes' (and their counterpart internal reads). They should do all that you need to convert either way between numbers and strings

Found them, thank you Bruce!

Seems kind of overhead-intensive. Is it? Or is that just my own mental hangover from the days when, when you wrote something to a file, you were actually writing to a physical 9-track tape?

So far I have gotten this done by taking the INT part and the FRACTIONal part, multiplying the fractional part by 1,000, INTing it, using CNUM on each, deleting extraneous spaces, and concatenating them into a single string with a period between them. (Speaking of overhead-intensive)

But hey, it works. Eventually.

In a perfect world, it would be nice if there was a single function for REAL numbers that does the same thing as CNUM, maybe with a format descriptor like F6.2 thrown in.

2 Sep 2010 8:33 #6887
character*80 str
real x
x = 42.7
write(str, '(f6.2)') x
print*, str
end
3 Sep 2010 5:50 #6898

Quoted from PaulLaidler

character*80 str
real x
x = 42.7
write(str, '(f6.2)') x
print*, str
end

Aw, that's WAY too easy and intuitive.

6 Sep 2010 10:31 #6911

Internal writes are great, BUT they always involve a few lines of code, and those lines of code always entail hard-coded data such as a format. So it's always a fag to implement one. Sometimes I think it would be fun to write a couple of routines that would bundle up all the gubbins into a single call once and for all. Then I wonder why no-one's done it yet and think it must not be as easy as it looks?

6 Sep 2010 2:30 #6913

Well, yes ... but the 'simple' case is only simple because it hides away, in its midst, a conscious decision on the part of the programmer as to exactly what the format should be. And the more complex case does not eliminate the need for that conscious decision, it just separates it out, which is a good thing in my book. Part of that decision is based on knowing whether the variable is integer or real or whatever, part of it is based on knowing how big the number is, and part of it is based on how precisely it needs to be represented.

The format ... aye, there's the rub. All the hard stuff either needs extra lines of code, or gets precomputed in the programmers head. Wouldn't it be nice to have a function:

char_variable = based_on_internal_write (variable)

(or even a small set of such functions, one for each numerical data type) that figured out all that stuff on its own?

6 Sep 2010 5:43 #6914

Quoted from sparge Internal writes are great, BUT they always involve a few lines of code, and those lines of code always entail hard-coded data such as a format. So it's always a fag to implement one. Sometimes I think it would be fun to write a couple of routines that would bundle up all the gubbins into a single call once and for all. Then I wonder why no-one's done it yet and think it must not be as easy as it looks?

I use the KREAL function of Simpleplot:

character20 rmax real8 rad_max integer*4 x,y x=... y=... rad_max=3.24264578 call kreal(real(rad_max),rmax) call draw_characters@(rmax,x,y,red)

The problem is that Simpleplot uses Real4, so that you need to convert a Real8 to real4....but at least for my purposes it works fine... I also wondered several times why Simpleplot had KREAL and FTN95 did not....but at least the Simpleplot library comes with the FTN95 compiler, so you can use it as a good alternative.....if real4 is enough for you...

Agustin

7 Sep 2010 1:20 #6922

Quoted from brucebowler And who figures 'exactly what the format should be' in that case other than 'the conscious decision on the part of the programmer'?

In the case of the internal write, it's 'in your face' what the format is. In your example, there's NO indication of what it might be (nor is there a mechanism to change it if the original programmer 'guessed wrong').

I think you are misunderstanding what I was trying to say. In my (pseudo-code) example, I meant to imply that the function would compute what the format should be.

The only 'mechanism' to change an incorrect guess is to recompile with a different guess. Are you saying that a hard-coded format is good because it's in your face, and because you can recompile if you get it wrong?

8 Sep 2010 9:58 #6924

I too work in a scientific environment, and have done for more than 25 years. I would be surprised if anyone making regular use of FORTRAN does *not *work in a scientific environment. So your 'I am here' postcard from the scientific high ground did not have to travel very far.

I am struggling to understand what misperception of yours or mine is getting under your skin so badly and generating such thinly-veiled hostility. I said that the hypothetical function would 'compute what the format should be'. Can you spot the key word? I even suggested what the first simple step in this computation could be. Somehow you translated this into 'some random format specified by something the user has no control over'.

With your science background, you ought at least to know what straw man reasoning is, even if you cannot yet recognise your own as such. However, I am surprised that your science background does not help you to see that a function is just as editable and recompilable as a format statement. I am also surprised that you classify a programmer 'guessing' a format as scientific.

9 Sep 2010 6:10 #6925

Trying to get the essence out of this: '(f6.2)' may be bad because 6 can't cope with 1000000 or 10000.12. If the programmer can pre-determine the range, he's fine. Pretty often he can't so he has to choose, possibly re-compiling if he's touching limits (or losing customers because the program just doesn't work).

Don't know how far a simple 'write(string,*) float' would get you to this, excluding specifying a minimum precision etc.

9 Sep 2010 7:05 #6926

I have used routines similar to the one below for many years.

      SUBROUTINE FORMS(V,STRING)

      CHARACTER*9 STRING,F(0:8)

      DATA F /'(0PF12.0)','(0PF12.1)','(0PF12.2)',
     *        '(0PF12.3)','(0PF12.4)','(0PF12.5)',
     *        '(0PF12.6)','(1PE12.4)','(F9.0,3X)'/

      Z=ABS(V)

        IF ((Z.GT.0.0.AND.Z.LT.0.001).OR.Z.GE.1.0E8) THEN
          K=7
        ELSE IF (Z.LT.1.0E-6)    THEN
          K=8
        ELSE IF (Z.LT.0.999995) THEN
          K=6
        ELSE IF (Z.LT.9.999995)  THEN
          K=5
        ELSE IF (Z.LT.99.99995)  THEN
          K=4
        ELSE IF (Z.LT.999.9995)  THEN
          K=3
        ELSE IF (Z.LT.9999.995)  THEN
          K=2
        ELSE IF (Z.LT.99999.95)  THEN
          K=1
        ELSE
          K=0
        END IF

      STRING=F(K)

      RETURN
      END
11 Sep 2010 1:27 #6931

Internal WRITEs are fast. In the Fortran-66 days, WRITEs were slow, but that wasn’t a code issue – it was due to the mechanical slowness of first line printers (or card or tape punches), then magnetic tapes.

You don’t need a rigidly fixed format like F6.2, because in an internal write the format can be contained in a character variable, e.g. if you know n and m (in Fn.m) then

WRITE (STRING1,’’’(F’,I3,’.’,I3,’)’’’ ) n, m
WRITE (STRING2, STRING1) x

(Apologies if I haven't got the right number of apostrophes. I usually use both single and double quotes - permissible since Fortran 90 - for readability, and several trial before getting it right).

In order to avoid lots of IFs, you can use the LOG10 function – although this only works for positive X, so

N1 = LOG10 ( ABS (X) )

where N1 is the number of characters before the decimal point for a number >1.0.

You may need to add 1 for a negative sign (and if you want a + plus sign). N1 is at least 1 more even for numbers <1.0 if you want a leading zero.

To get n, you need to consider the desired number of decimal places, plus N1 + 1, where the extra 1 if for the decimal point.

(It is possible to write X with a big n, then remove leading blank characters, but I prefer LOG10).

There is a maximum meaningful n, due to the number of significant contained decimal digits of precision (7 in REAL*4 ?). This used to be a big problem with all the different formats in mainframes (16, 24, 30, 32, 36 and 60 bit words in my personal experience, plus all the complexities of DOUBLE PRECISION), but now all we need to consider are 32, 64 and 80 bit precisions (and not even the latter in .NET). There are also practical limits on what values of n and m are sensible before scientific notation is anyway a more sensible option (for an example, see what scientific calculators do!).

A general purpose floating point variant of CNUM would also need to error-handle undefined numbers and special cases like NaN.

Most applications have intrinsic limits on range and precision for variables that contain physical values. For example, no distance on the planet earth can be more than 40 000 000 metres (plus a tiny bit!) or be negative, hence 2 < =N1 < = 8. Moreover, if a millimetre accuracy is adequate, then we can probably fix m=3, and n therefore between 5 and 12. I am sure that other forum users have their own examples. It probably means that even though n and m can in principle be calculated, the programmer probably needs to have some control over what is actually selected, even if they do not need to choose,* a priori*, what n and m are.

CNUM is a lot easier than the floating point equivalent because the range for integers is small, and the precision absolute.

11 Sep 2010 2:49 #6932

Since Fortran 90, using n=0 is a good alternative, such as fmt='(f0.2)' or fmt='(1x,f0.2)'. There is also the G format, which I don't use. I prefer to control the m else use the ES format. If the number is very small I use ' 0. '

John

Please login to reply.