Fortran Format?

OK, I have an algorithm that I created to format a series of numbers
for a column centric FORTRAN routine to use. I don’t like what I have
created, although it works, so I would like to ask if anyone here has
a more cleaver way.

Problem: I have a series of numbers that need to be formated as a
FORTRAN program would. That is, FORTRAN cares more about columns than
numbers so I need to fake the output of Ruby to make it look “decimal
justified”.

Example, a series of numbers:
3.15, 122.5, 303.123, 55.0
Input for C or Ruby (the space means a new number):
3.15 122.5
303.123 55.0
Input needed for FORTRAN with format (f7.3,f5.1):
3.150122.5
303.123 55.0

My Ruby hack to put spaces at the begining if necessary:
def ff(num,len1,len2)
x = num.to_s.split(".")
numstring = ""
x[0].size.upto(len1 - 1) {|b| numstring << ’ '}
numstring << x[0] << "."
numstring << x[1][0…len2]
end

code…
bla …
printf("%s %s\n", ff(3.150,3,3),ff(122.5,3,1)
printf("%s %s\n", ff(303.123,3,3),ff(55.0,3,1)

I know that this needs improvement so your help would be appreciated.
I have to interface with these types of FORTRAN programs a lot, thus
far I have avoided this.
Thanks,
Chris

Qubert wrote:

printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1)
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1)

More like

printf(“%7.3f%5.1f\n”,3.15,122.5)

Hal

Qubert wrote:

OK, I have an algorithm that I created to format a series of numbers
for a column centric FORTRAN routine to use. I don’t like what I have
created, although it works, so I would like to ask if anyone here has
a more cleaver way.

Problem: I have a series of numbers that need to be formated as a
FORTRAN program would. That is, FORTRAN cares more about columns than
numbers so I need to fake the output of Ruby to make it look “decimal
justified”.

Example, a series of numbers:
3.15, 122.5, 303.123, 55.0
Input for C or Ruby (the space means a new number):
3.15 122.5
303.123 55.0
Input needed for FORTRAN with format (f7.3,f5.1):
3.150122.5
303.123 55.0

My Ruby hack to put spaces at the begining if necessary:
def ff(num,len1,len2)
x = num.to_s.split(“.”)
numstring = “”
x[0].size.upto(len1 - 1) {|b| numstring << ’ '}
numstring << x[0] << “.”
numstring << x[1][0…len2]
end

code…
bla …
printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1)
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1)

A better way would be to be to use the sprintf method (documented on
page 427 of the pickaxe) to format the string.

The following code does what you want

def ff(num, len1, len2)
sprintf(“%#{len1 + len2 + 1}.#{len2}f”, num)
end

printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1))
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1))

I know that this needs improvement so your help would be appreciated.
I have to interface with these types of FORTRAN programs a lot, thus
far I have avoided this.

HTH

···

Mark Sparshatt

I know that this needs improvement so your help would be appreciated.
I have to interface with these types of FORTRAN programs a lot, thus
far I have avoided this.

maybe:

“%7.3f%5.1f\n” % [3.15,122.5]
=> " 3.150122.5\n"

···

il 19 May 2004 14:40:13 -0700, qubert@orbit.gotdns.com (Qubert) ha scritto::

How about calling your FORTRAN routines directly from ruby?

I recently started on a Fortran-oriented linear algebra package in
which I do this. However I put off working on it until I was
convinced a show-stopper crash in ruby/dl could be fixed. As it so
happens, it was fixed today [ruby-core:2095].

I have yet to form a project on rubyforge, but probably all you need
is the following example:

require ‘dl/import’
require ‘dl/struct’
require ‘evil’ # http://evil.rubyforge.org

module Lapack
extend DL::Importable

dlload “liblapack.so”
dlload “libblas.so”
dlload “libf2c.so”

typealias “doublereal”, “double”
typealias “integer”, “int”
typealias “ftnlen”, “short”

def self.prototype s
func, args = s.strip.gsub(%r!\s+!, " “).split(%r![()]!)
args = args.gsub(%r!(\w+[\s])\w*!){$1}.gsub(%r!\s+!,”")
extern “#{func}(#{args})”
end

prototype %{
void s_copy(char *a, char *b, ftnlen la, ftnlen lb);
}

prototype %{
int dgemm_(char *transa,
char *transb,
integer *m,
integer *n,
integer *k,
doublereal *alpha,
doublereal *a,
integer *lda,
doublereal *b,
integer *ldb,
doublereal *beta,
doublereal *c,
integer *ldc)
}
end

class DMatrix
ELEMTYPE = “d”
ELEMTYPE_GLOB = “d*”

attr_reader :vsize, :hsize

def initialize(columns, copy = true)
@vsize = columns[0].size
@hsize = columns.size
if copy
@columns = columns.map { |col| col.map { |e| e.to_f } }
else
@columns = columns
end
end

def self.columns(columns, copy = true)
self.new(columns, copy)
end

def (i, j) ; @columns[j][i] ; end
def =(i, j, e) ; @columns[j][i] = e.to_f ; end

def to_s
res = “”
(0…vsize).each { |i|
(0…hsize).each { |j|
res << sprintf(“% 10-.6f”, self[i,j])
}
res << “\n”
}
res
end

def data
@columns.flatten.pack(ELEMTYPE_GLOB)
end

def self.data(vsize, hsize, data)
flat = data.unpack(ELEMTYPE_GLOB)
cols = (0…hsize).map { flat.slice!(0, vsize) }
self.new(cols, false)
end

def *(other)
m = self.vsize
n = other.hsize
k = other.vsize

  raise "matrix size mismatch" unless self.hsize == k
     
  a = self
  b = other
  c_data = [0.0].pack(ELEMTYPE)*(m*n)
     
  begin
     # prevent dangling pointers
     GC.disable

     Lapack.dgemm_("N",                 # transa
                   "N",                 # transb
                   [m].to_ptr,          # m
                   [n].to_ptr,          # n
                   [k].to_ptr,          # k
                   [1.0].to_ptr,        # alpha
                   a.data.internal.ptr, # a
                   [m].to_ptr,          # lda
                   b.data.internal.ptr, # b
                   [k].to_ptr,          # ldb
                   [0.0].to_ptr,        # beta
                   c_data.internal.ptr, # c
                   [n].to_ptr)          # ldc
  ensure
     GC.enable
  end
  DMatrix.data(m, n, c_data)

end
end

a = DMatrix.columns [ [1,2], [3,4], [5,6], [7,8] ]
b = DMatrix.columns [ [9,10,11,12], [13,14,15,16] ]
[a, b, a*b].each { |m|
puts “-”*50
puts m
}

···

— Qubert qubert@orbit.gotdns.com wrote:

OK, I have an algorithm that I created to format a series of numbers
for a column centric FORTRAN routine to use. I don’t like what I have
created, although it works, so I would like to ask if anyone here has
a more cleaver way.


Do you Yahoo!?
Yahoo! Domains – Claim yours for only $14.70/year
http://smallbusiness.promotions.yahoo.com/offer

this will not work on ‘too wide’ numbers as printf never truncates, eg:

~ > cat a.rb
def ff(num, len1, len2); sprintf(“%#{len1 + len2 + 1}.#{len2}f”, num); end

puts(ff(12345.12345, 3, 3))

~ > ruby a.rb
12345.123

the fortan format specifier says that the output/input will be EXACTLY as
wide as specified - not expanded. in otherwords it WILL truncate on output
and respect columns (not whitespace like scanf) in input. it’s really a
terrible thing ;-(. in any case, something like this may work:

~ > cat b.rb
def ff num, len1, len2
(sprintf “%#{ len1 }.#{ len2 }f”, num)[0…len1]
end
puts(ff(12345.12345, 3, 3))
puts “#{ ff 3.15, 7, 3 }#{ ff 122.5, 5, 1 }”
puts “#{ ff 303.123, 7, 3 }#{ ff 55.0, 5, 1 }”

~ > ruby b.rb
123
3.150122.5
303.123 55.0

but my fortran is rusty… i forget if the decimal bit is required? if so this
won’t work since it may eject the mantissa… so, truncation is needed to
enforce field width but i’m not positive this is the correct method of
truncation… hopefully, since you are working with fortran actively, you will
know the answer to this :wink:

cheers.

-a

···

On Thu, 20 May 2004, Mark Sparshatt wrote:

Qubert wrote:

OK, I have an algorithm that I created to format a series of numbers
for a column centric FORTRAN routine to use. I don’t like what I have
created, although it works, so I would like to ask if anyone here has
a more cleaver way.

Problem: I have a series of numbers that need to be formated as a
FORTRAN program would. That is, FORTRAN cares more about columns than
numbers so I need to fake the output of Ruby to make it look “decimal
justified”.

Example, a series of numbers:
3.15, 122.5, 303.123, 55.0
Input for C or Ruby (the space means a new number):
3.15 122.5
303.123 55.0
Input needed for FORTRAN with format (f7.3,f5.1):
3.150122.5
303.123 55.0

My Ruby hack to put spaces at the begining if necessary:
def ff(num,len1,len2)
x = num.to_s.split(“.”)
numstring = “”
x[0].size.upto(len1 - 1) {|b| numstring << ’ '}
numstring << x[0] << “.”
numstring << x[1][0…len2]
end

code…
bla …
printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1)
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1)

A better way would be to be to use the sprintf method (documented on
page 427 of the pickaxe) to format the string.

The following code does what you want

def ff(num, len1, len2)
sprintf(“%#{len1 + len2 + 1}.#{len2}f”, num)
end

printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1))
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1))

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
“640K ought to be enough for anybody.” - Bill Gates, 1981
===============================================================================

oops, that’s [ruby-core:2905]

···

— Jeff Mitchell quixoticsycophant@yahoo.com wrote:

it was fixed today [ruby-core:2095].


Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

“Mark Sparshatt” msparshatt@yahoo.co.uk schrieb im Newsbeitrag
news:40ABD8AF.6020500@yahoo.co.uk

Qubert wrote:

OK, I have an algorithm that I created to format a series of numbers
for a column centric FORTRAN routine to use. I don’t like what I have
created, although it works, so I would like to ask if anyone here has
a more cleaver way.

Problem: I have a series of numbers that need to be formated as a
FORTRAN program would. That is, FORTRAN cares more about columns than
numbers so I need to fake the output of Ruby to make it look “decimal
justified”.

Example, a series of numbers:
3.15, 122.5, 303.123, 55.0
Input for C or Ruby (the space means a new number):
3.15 122.5
303.123 55.0
Input needed for FORTRAN with format (f7.3,f5.1):
3.150122.5
303.123 55.0

My Ruby hack to put spaces at the begining if necessary:
def ff(num,len1,len2)
x = num.to_s.split(“.”)
numstring = “”
x[0].size.upto(len1 - 1) {|b| numstring << ’ '}
numstring << x[0] << “.”
numstring << x[1][0…len2]
end

code…
bla …
printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1)
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1)

A better way would be to be to use the sprintf method (documented on
page 427 of the pickaxe) to format the string.

The following code does what you want

def ff(num, len1, len2)
sprintf(“%#{len1 + len2 + 1}.#{len2}f”, num)
end

sprintf can already handle widths as arguments:

sprintf( “%*.*f”, len1 + len2, len2, num )

printf(“%s %s\n”, ff(3.150,3,3),ff(122.5,3,1))
printf(“%s %s\n”, ff(303.123,3,3),ff(55.0,3,1))

printf “%*.f %.*f\n”, 7, 3, 3.150, 5, 1, 122.5
3.150 122.5

:slight_smile:

robert
···

I know that this needs improvement so your help would be appreciated.
I have to interface with these types of FORTRAN programs a lot, thus
far I have avoided this.

HTH

Mark Sparshatt