3

Is there a way to change the period decimal separator for a comma?.

Also, how can I make the output numbers have a thousand separator?. This could be a comma, a period, a space ...

Antonio Serrano
  • 385
  • 2
  • 15

3 Answers3

4

Use the Argument DECIMAL='COMMA' when opening a file

open(100,file=logfile,status='unknown',DECIMAL='COMMA')

This will change the decimal to comma

why.n0t
  • 432
  • 7
  • 21
4

You can write a C++ function which will convert the number in a string in you current locale for you.

#include <string>
#include <iomanip> 
#include <sstream>

class SpaceSeparator: public std::numpunct<char>
{
public:
    SpaceSeparator(std::size_t refs): std::numpunct<char>(refs) {}
protected:
    char do_thousands_sep() const { return ' '; }
    char do_decimal_point() const { return ','; }
    std::string do_grouping() const { return "\03"; }
};

extern "C" {

void convert(char* str, double f, int len) {
  std::string s;
  std::stringstream out;
  SpaceSeparator facet(1); //1 - don't delete when done
  std::locale prev = out.imbue(std::locale(std::locale(), &facet));
  out << std::setprecision(15) << f;

  s = out.str();
  std::copy(s.begin(), s.end(), str);
  int i;
  for (i=s.size();i<len;i++){
    str[i] = ' ';
  }
}

}

call from Fortran:

  use iso_c_binding

  interface
    subroutine convert(str, f, l) bind(C,name="convert")
      import
      character(c_char) :: str(*)
      real(c_double), value :: f
      integer(c_int), value :: l
    end subroutine
  end interface

  character(len=100,kind=c_char) :: ch

  call convert(ch, 123456.123_c_double, len(ch, kind=c_int))
  print *,ch
end

On my machine it prints 123 456,123:

> gfortran locale.cc locale.f90 -lstdc++
> ./a.out 
 123 456,123                                

Disclaimer: I am not a C++ programmer and he solution can be slow. Maybe the brute force approach in Fortran is better.

I used this answer as a base: https://stackoverflow.com/a/2648663/721644

Community
  • 1
  • 1
2

a quick and dirty fortran based approach:

  implicit none

  write(*,*) commadelim(123456.789)
  write(*,*) commadelim(23456.789)
  write(*,*) commadelim(3456.789)
  write(*,*) commadelim(-123456.789)
  write(*,*) commadelim(-23456.789)
  write(*,*) commadelim(-3456.789)

  contains

    function commadelim(v)
      implicit none

      real v
      integer dp,p,z0,i
      character(len=50) :: commadelim

      write(commadelim,'(f0.12)') abs(v)      
      dp = index(commadelim,'.')
      commadelim(dp:dp) = ','
      z0 = 2 - mod(dp+1,3)

      do i = 1, (dp+z0-1)/3-1
        p = 4*i-z0
        commadelim = commadelim(:p)//'.'//commadelim(p+1:)
      enddo

      if (v<0) commadelim = '-'//commadelim
    end function
  end
agentp
  • 6,849
  • 2
  • 19
  • 37
  • I really didn't understand this code, but I realize now that it deals with both thousand separators and the decimal separator. – Antonio Serrano Aug 29 '14 at 11:38
  • Which is more efficient, this code or the C++ code?. – Antonio Serrano Aug 29 '14 at 11:39
  • Efficiency has to be measured, but probably this one could be expected to be more efficient. It just manually forms the string from the number. It is straightforward Fortran, but for start you can just copy and paste the function. – Vladimir F Героям слава Aug 29 '14 at 12:24
  • how much data are you writing with thousands separators that efficiency is important? I like the self contained fortran for portability. OTOH it may take more work to ensure it is robust, plus you'll need to do some work to generalize to other format descriptors. – agentp Aug 29 '14 at 15:31
  • The code above has some errors, so it puts the comma in a wrong place and sometimes eliminates some digits. So, I will remake it and public it here. – Antonio Serrano Oct 27 '14 at 16:24