Write float arrays to a text file: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
m (→‎{{header|C++}}: minor cleanups)
Line 138: Line 138:
<lang cpp>
<lang cpp>
template<class InputIterator, class InputIterator2>
template<class InputIterator, class InputIterator2>
void writedat(const std::string& filename,
void writedat(const char* filename,
InputIterator xbegin, InputIterator xend,
InputIterator xbegin, InputIterator xend,
InputIterator2 ybegin, InputIterator2 yend,
InputIterator2 ybegin, InputIterator2 yend,
Line 145: Line 145:
std::ofstream f;
std::ofstream f;
f.exceptions(std::ofstream::failbit | std::ofstream::badbit);
f.exceptions(std::ofstream::failbit | std::ofstream::badbit);
f.open(filename.c_str());
f.open(filename);
for ( ; xbegin != xend and ybegin != yend; ++xbegin, ++ybegin)
for ( ; xbegin != xend and ybegin != yend; ++xbegin, ++ybegin)
f << std::setprecision(xprecision) << *xbegin << "\t"
f << std::setprecision(xprecision) << *xbegin << '\t'
<< std::setprecision(yprecision) << *ybegin << "\n";
<< std::setprecision(yprecision) << *ybegin << '\n';
}
}
</lang>
</lang>
Line 154: Line 154:
<lang cpp>
<lang cpp>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <cmath> // ::sqrt()
#include <fstream>
#include <fstream>
#include <iomanip>
#include <iomanip> // setprecision()
#include <iostream>
#include <iostream>
#include <iterator> // back_inserter()
#include <string>
#include <string>
#include <vector>
#include <vector>
Line 168: Line 167:
double x[] = {1, 2, 3, 1e11};
double x[] = {1, 2, 3, 1e11};
const size_t xsize = sizeof(x) / sizeof(*x);
const size_t xsize = sizeof(x) / sizeof(*x);
std::vector<double> y;
std::vector<double> y(xsize);
std::transform(&x[0], &x[xsize], std::back_inserter(y), ::sqrt);
std::transform(&x[0], &x[xsize], y.begin(), ::sqrt);


// write file using default precisions
// write file using default precisions
Line 176: Line 175:
// print the result file
// print the result file
std::ifstream f("sqrt.dat");
std::ifstream f("sqrt.dat");
for (std::string line; std::getline(f, line); line.clear())
for (std::string line; std::getline(f, line); )
std::cout << line << std::endl;
std::cout << line << std::endl;
}
}

Revision as of 05:04, 4 February 2009

Task
Write float arrays to a text file
You are encouraged to solve this task according to the task description, using any language you may know.

Write two equal-sized numerical arrays `x' and `y' to a two-column text file named `filename'.

The first column of the file contains values from an `x'-array with a given `xprecision', the second -- values from `y'-array with `yprecision'.

For example, considering:

   x = {1, 2, 3, 1e11};
   y = {1, 1.4142135623730951, 1.7320508075688772, 316227.76601683791}; /* sqrt(x) */
   xprecision = 3;
   yprecision = 5;

The file is:

   1    1
   2    1.4142
   3    1.7321
   1e+011   3.1623e+005

This task is intended as a subtask for Measure relative performance of sorting algorithms implementations.

Ada

<lang ada> with Ada.Text_IO; use Ada.Text_IO; with Ada.Float_Text_IO; use Ada.Float_Text_IO; with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;

procedure Write_Float_Array is

  type Float_Array is array (1..4) of Float;
  procedure Write_Columns
            (  File   : File_Type;
               X      : Float_Array;
               Y      : Float_Array;
               X_Pres : Natural := 3;
               Y_Pres : Natural := 5
            ) is
  begin
     for I in Float_Array'range loop
        Put (File => File, Item => X(I), Fore => 1, Aft => X_Pres - 1);
        Put (File, " ");
        Put (File => File, Item => Y(I), Fore => 1, Aft => Y_Pres - 1);
        New_Line (File);
     end loop;
  end Write_Columns;
  
  File : File_Type;
  X : Float_Array := (1.0, 2.0, 3.0, 1.0e11);
  Y : Float_Array;

begin

  Put ("Tell us the file name to write:");
  Create (File, Out_File, Get_Line);
  for I in Float_Array'range loop
     Y(I) := Sqrt (X (I));
  end loop;
  Write_columns (File, X, Y);
  Close (File);

end Write_Float_Array; </lang>

ALGOL 68

 
PROC writedat = (STRING filename, []REAL x, y, INT x width, y width)VOID: (
  FILE f;
  INT errno = open(f, filename, stand out channel);
  IF errno NE 0 THEN stop FI;
  FOR i TO UPB x DO
    # FORMAT := IF the absolute exponent is small enough, THEN use fixed ELSE use float FI; #
    FORMAT repr x := ( ABS log(x[i])<x width | $g(-x width,x width-2)$ | $g(-x width,x width-4,-1)$ ),
           repr y := ( ABS log(y[i])<y width | $g(-y width,y width-2)$ | $g(-y width,y width-4,-1)$ );
    putf(f, (repr x, x[i], $" "$, repr y, y[i], $l$))
  OD;
  close(f)
);

Example usage:

 
[]REAL x = (1, 2, 3, 1e11);
[UPB x]REAL y; FOR i TO UPB x DO y[i]:=sqrt(x[i]) OD;
printf(($"x before:"$, $xg$, x, $l$));
printf(($"y before:"$, $xg$, y, $l$));
writedat("sqrt.dat", x, y, 3+2, 5+2);

printf($"After:"l$);
FILE sqrt dat;
INT errno = open(sqrt dat, "sqrt.dat", stand in channel);
IF errno NE 0 THEN stop FI;
on logical file end(sqrt dat, (REF FILE sqrt dat)BOOL: stop);
TO UPB x DO
  STRING line;
  get(sqrt dat, (line, new line));
  print((line,new line))
OD

Output:

x before: +1.00000000000000e  +0 +2.00000000000000e  +0 +3.00000000000000e  +0 +1.00000000000000e +11
y before: +1.00000000000000e  +0 +1.41421356237310e  +0 +1.73205080756888e  +0 +3.16227766016838e  +5
After:
1.000 1.00000
2.000 1.41421
3.000 1.73205
 1e11  316228

C

<lang c>

  1. include <stdio.h>
  2. include <math.h>

int main(int argc, char **argv) {

  float x[4] = {1,2,3,1e11}, y[4];
  int i = 0;
  FILE *filePtr;
  filePtr = fopen("floatArray","w");
  for (i = 0; i < 4; i++) {
     y[i] = sqrt(x[i]);
     if (x[i] > 10000 || x[i] < .00001 || y[i] > 10000 || y[i] < .00001) {
        /* profoundly arbitrary on my part */
        fprintf(filePtr, "%1.3e\t%1.5e\n", x[i], y[i]);
     } else {
        fprintf(filePtr, "%1.3f\t%1.5f\n", x[i], y[i]);
     }
  }
  return 0;

} </lang>

The file "floatArray" then contains the following:

1.000   1.00000
2.000   1.41421
3.000   1.73205
1.000e+11       3.16228e+05

C++

Function writedat(): <lang cpp>

 template<class InputIterator, class InputIterator2>
 void writedat(const char* filename,
               InputIterator xbegin, InputIterator xend,
               InputIterator2 ybegin, InputIterator2 yend,
               int xprecision=3, int yprecision=5)
 {
   std::ofstream f;
   f.exceptions(std::ofstream::failbit | std::ofstream::badbit);
   f.open(filename);
   for ( ; xbegin != xend and ybegin != yend; ++xbegin, ++ybegin)
     f << std::setprecision(xprecision) << *xbegin << '\t'
       << std::setprecision(yprecision) << *ybegin << '\n';
 }

</lang> Example: <lang cpp>

 #include <algorithm>
 #include <cmath>    // ::sqrt()
 #include <fstream>
 #include <iomanip>  // setprecision()
 #include <iostream>
 #include <string>
 #include <vector>
 int main()
 {
   try {
     // prepare test data
     double x[] = {1, 2, 3, 1e11};
     const size_t xsize = sizeof(x) / sizeof(*x);
     std::vector<double> y(xsize);
     std::transform(&x[0], &x[xsize], y.begin(), ::sqrt);
     // write file using default precisions
     writedat("sqrt.dat", &x[0], &x[xsize], y.begin(), y.end());
     // print the result file
     std::ifstream f("sqrt.dat");
     for (std::string line; std::getline(f, line); )
       std::cout << line << std::endl;
   }
   catch(std::exception& e) {
     std::cerr << "writedat: exception: '" << e.what() << "'\n";
     return 1;
   }
   return 0;
 }

</lang> Result:

1       1
2       1.4142
3       1.7321
1e+11   3.1623e+05

Fortran

In ANSI FORTRAN 77 or later use OPEN STATEMENT, and formatted WRITE statement with implied DO loop:

     real x(4), y(4)
     data x / 1.0, 2.0, 4.0, 1.0e11 /
     
     do 10 i = 1, 4
        y = sqrt(x)
  10 continue
     
     open(unit=15, file='two_cols.txt', status='new')
     write(15,'(f20.3,f21.4)') (x(I), y(I), I = 1, 4)
     end

Haskell

Probably not very idiomatic but oh well

import System.IO
import Text.Printf
import Control.Monad

writeDat filename x y xprec yprec =
  do h <- openFile filename WriteMode
     -- Haskell's printf doesn't support a precision given as an argument for some reason, so we insert it into the format manually:
     let writeLine = hPrintf h ("%." ++ show xprec ++ "g\t%." ++ show yprec ++ "g\n")
     zipWithM_ writeLine x y
     hClose h

Example usage

Prelude> let x = [1, 2, 3, 1e11]
Prelude> let y = map sqrt x
Prelude> y
[1.0,1.4142135623730951,1.7320508075688772,316227.7660168379]
Prelude> writeDat "sqrt.dat" x y 3 5
Prelude> readFile "sqrt.dat" >>= putStr
1.000	1.00000
2.000	1.41421
3.000	1.73205
1.000e11	316227.76602

IDL

; the data:
x = [1,2,3,1e11]
y=sqrt(x)
xprecision=3
yprecision=5
 
; NOT how one would do things in IDL, but in the spirit of the task - the output format:
form = string(xprecision,yprecision,format='("(G0.",I0.0,",1x,G0.",I0.0,")")')
 
; file I/O:
openw,unit,"datafile.txt",/get
  for i = 1L, n_elements(x) do printf, unit, x[i-1],y[i-1],format=form
free_lun,unit

The file "datafile.txt" then contains the following:

1 1
2 1.4142
3 1.7321
1E+011 3.1623E+005

This is fairly ugly and un-IDLish. For example one shouldn't just rely on x and y having the same size. And if data is output in human-readable form, it should probably be lined up more nicely. And if it really has to be in two-column format with x and y side by side, one might consider running ASCII_Template or some such instead of that ugly hand-formatting.

J

   require 'files'            NB.  for fwrites
   
   x          =.  1 2 3 1e11
   y          =.  %: x        NB.  y is sqrt(x)
   
   xprecision =.  3
   yprecision =.  5
   
   filename   =.  'whatever.txt'
   
   data       =.  (0 j. xprecision,yprecision) ": x,.y
   
   data fwrites filename

OCaml

<lang ocaml>let write_dat filename x y ?(xprec=3) ?(yprec=5) () =

 let oc = open_out filename in
 let write_line a b = Printf.fprintf oc "%.*g\t%.*g\n" xprec a yprec b in
   List.iter2 write_line x y;
   close_out oc</lang>

Example usage

# let x = [1.0; 2.0; 3.0; 1e11];;
val x : float list = [1.; 2.; 3.; 100000000000.]
# let y = List.map sqrt x;;
val y : float list =
  [1.; 1.41421356237309515; 1.73205080756887719; 316227.766016837908]
# write_dat "sqrt.dat" x y ();;
- : unit = ()
# let ic = open_in "sqrt.dat";;
val ic : in_channel = <abstr>
# try
    while true do
      print_endline (input_line ic)
    done
  with End_of_file -> ();;
1	1
2	1.4142
3	1.7321
1e+11	3.1623e+05
- : unit = ()

Perl

<lang perl>sub writedat {

   my ($filename, $x, $y, $xprecision, $yprecision) = @_;
   $xprecision ||= 3;
   $yprecision ||= 5;
   open FH, ">$filename" or die "Can't open file: $!";
   foreach my $i (0 .. $#$x) {
       printf FH "%.*g\t%.*g\n", $xprecision, $x->[$i], $yprecision, $y->[$i];
   }
   close FH;

}

my @x = (1, 2, 3, 1e11); my @y = map sqrt, @x;

writedat("sqrt.dat", \@x, \@y);</lang> File contents

1	1
2	1.4142
3	1.7321
1e+11	3.1623e+05

Python

Works with: Python version 2.6

<lang python>import itertools def writedat(filename, x, y, xprecision=3, yprecision=5):

   with open(filename,'w') as f:
       for a, b in itertools.izip(x, y):
           print >> f, "%.*g\t%.*g" % (xprecision, a, yprecision, b)</lang>

Example usage <lang python>

>>> import math
>>> x = [1, 2, 3, 1e11]
>>> y = map(math.sqrt, x)
>>> y
[1.0, 1.4142135623730951, 1.7320508075688772, 316227.76601683791]
>>> writedat("sqrt.dat", x, y)
>>> # check 
...
>>> for line in open('sqrt.dat'):
...   print line,
...
1       1
2       1.4142
3       1.7321
1e+011  3.1623e+005

</lang>

Works with: Python version 3

<lang python>def writedat(filename, x, y, xprecision=3, yprecision=5):

   with open(filename,'w') as f:
       for a, b in zip(x, y):
           print("%.*g\t%.*g" % (xprecision, a, yprecision, b), file=f)
           #or, using the new-style formatting:
           #print("{1:.{0}g}\t{3:.{2}g}".format(xprecision, a, yprecision, b), file=f)</lang>

Ruby

<lang ruby>

  1. prepare test data

x = [1, 2, 3, 1e11] y = x.collect { |xx| Math.sqrt xx } xprecision = 3 yprecision = 5

  1. write the arrays

open('sqrt.dat', 'w') do |f|

 x.zip(y) { |xx, yy| f.printf("%.*g\t%.*g\n", xprecision, xx, yprecision, yy) }

end

  1. print the result file

open('sqrt.dat', 'r') { |f| puts f.read } </lang> Result: <lang ruby> 1 1 2 1.4142 3 1.7321 1e+11 3.1623e+05 </lang>