Fortran decimal and thousand separator

2019-08-04 04:21发布

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 ...

3条回答
Emotional °昔
2楼-- · 2019-08-04 04:57

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
查看更多
Deceive 欺骗
3楼-- · 2019-08-04 05:01

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

查看更多
Deceive 欺骗
4楼-- · 2019-08-04 05:10

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

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

This will change the decimal to comma

查看更多
登录 后发表回答