views:

87

answers:

4

I am working with a Fortran program that expects floating point numbers to be input using Fortran's E format specifier, which is scientific notation, except the mantissa must be between 0 and 1. So instead of:

"3147.3" --> "3.1473E3",

it needs

"3147.3" --> "0.31473E4".

I am unable to modify the Fortran program, as it works with a few other programs that are also particular.

It would appear that the C# E format string would give me the former. Is there any simple way to achieve the latter in C#?

A: 

The representaiton of floats or doubles are defined in IEEE754 / IEC 60559:1989. You should look to find libraries to extract mantissa and exponent. Then you could just divide by then to move to comma and subtract the number of steps from the exponent to form your solution.

schoetbi
+2  A: 

You could specify a custom format like so.

var num = 3147.3;
num.ToString("\\0.#####E0"); // "0.31473E4"
Jeff M
That seems to be perfect. Works for negative numbers and works fine with my padding. I needed to always have 3 digits of precision and pad to a width of 10, so I used `string.Format("{0,10:\\0.000E0}", -.125)`
notJim
A: 

You could take something similar to Jeff M's solution, and implement it via extension method:

public static class DoubleExtensions
{
    public static string ToFortranDouble(this double value)
    {
        return value.ToString("\\0.#####E0");
    }
}

class Program
{
    static void Main(string[] args)
    {
        string fortranValue = 3147.3.ToFortranDouble();
        System.Console.WriteLine(fortranValue);
    }
}

Or for something a little more complicated (not sure how much precision Fortran floats/doubles give):

public static class DoubleExtensions
{
    public static string ToFortranDouble(this double value)
    {
        return value.ToFortranDouble(4);
    }

    public static string ToFortranDouble(this double value, int precision)
    {
        return string.Format(value.ToString(
            string.Format("\\0.{0}E0", new string('#', precision))
            ));
    }
}
Merlyn Morgan-Graham
I managed to work out the leading zero problem. Just had to escape it.
Jeff M
I'm actually passing this through `string.format` anyway, so it doesn't matter if I need to through a 0 in front of it.
notJim
Actually, I don't think this works with negative numbers (they become `0-1E3`, for example). Also, I'm padding the number field to a width of 10 (but you didn't know that, of course).
notJim
Award Jeff the answer if he nails it, btw. I'm just showing some syntax that will shorten whatever the correct answer is.
Merlyn Morgan-Graham
@notJim: What does -3147.3 become in this example? Maybe Jeff can code that up for you, too? :)
Merlyn Morgan-Graham
I'm not sure what you're getting at. Yours gives 0-.31473E4 while Jeff's gives -0.31473E4.
notJim
@notJim: Oh yeah. He edited his answer to fix the format string instead of pre-pending it, so I fixed my prepend hack to match his correct format string.
Merlyn Morgan-Graham
+1  A: 

I think that you are solving a non-existent problem. It is true that the default of the Fortran E output specifier has a leading zero before the decimal point (this can be modified). But when the E specifier is used for input it is very tolerant and does not require the leading zero -- if you have a decimal point in the number and the number fits within the columns specified by the format, it will work.

Here is an example Fortran program, and an example input file.

program test_format

real :: num1, num2, num3

open (unit=16, file="numbers_3.txt", status='old', access='sequential', form='formatted', action='read' ) 

read (16, 1010 ) num1
read (16, 1010 ) num2
read (16, 1010 ) num3

1010 format (E9.5)

write (*, *) num1, num2, num3

stop

end program test_format

and the sample input with three different cases:

3.1473E3
0.31473E4
3147.3

I tested the program with gfortran and Intel ifort. The output was:

 3147.300       3147.300       3147.300

So when performing input using Fortran's E format specifier, it is not necessary that the digit before the decimal point be zero. It is not even necessary that the input value use E-notation!

Edit / P.S. I translated the program to the fixed-form source layout of FORTRAN 77 and compiled it with g77 -- it read the three test numbers just fine. The E-format has been flexible for input for a long time -- probably since FORTRAN IV, perhaps longer.

M. S. B.
Huh, thanks for the info, but I'm definitely having an issue with this. I'm automatically generating an input file for the fortran program, and it's just hanging, waiting for input it recognizes, or crashing. Maybe it's because it's reading multiple inputs from a single line? Here's an example of one of my format strings that's had issues when I play fast-and-loose with the format: `READ (NREAD,1365) (ABC(I),I=1,NABC)` with: `1365 format(8f10.5)`. It might have more to do with the width of the field I guess. Anyway, the solutions here are working fine, so I'm not worried about it.
notJim
Sir, you have A LOT of Fortran in your history. I do not envy you, but I'm glad you're here!
notJim
The key with the format 8f10.5 is that you have eight fields of 10 columns. The rigid part of this format is that each number has to fit within its field of 10 columns or it will get truncated. For example, if your first number only needs 5 characters, you have to add five spaces before you output the second number. If NABC > 8, place 8 numbers per line and Fortran should advance to the next line, reusing the format. Also, some Fortran compilers might insist on a line terminator at the end of the line.
M. S. B.
I've only seen one book on FORTRAN II (the precursor to FORTRAN IV), and that was forty (40) years ago. My recollection today is that E forman on input was permissive this way even in FORTRAN II.
John R. Strohm