roygvib
roygvib

Reputation: 7395

Output precision of `writeln()` for floating-point numbers

Using writef(), I can control the output precision of a floating-point number, for example:

writef( "%20.15dr\n", 1.0 / 3.0 );      // 0.333333333333333

but if I use writeln() for convenience, the number is output with 6 digits:

writeln( 1.0 / 3.0 );                   // 0.333333

Is there possibly a way to control the default output precision of floating-point numbers for writeln()..? (e.g., via some environment variable?)

For comparison, some languages output 15 digits and some 6 digits by default, so the result seems to vary depending on languages (or compilers).

# python2
print 1.0 / 3.0      # 0.333333333333
# python3
print( 1.0 / 3.0 )   # 0.3333333333333333
# julia
println( 1.0 / 3.0 )   # 0.3333333333333333
# gfortran
print *, 1.0d0 / 3.0d0   # 0.33333333333333331
# swift
print( 1.0 / 3.0 )       # 0.333333333333333
# nim
echo( 1.0 / 3.0 )       # 0.3333333333333333
# g++
cout << 1.0 / 3.0 << endl;   # 0.333333
# d (dmd)
writeln( 1.0 / 3.0 );      # 0.333333

Upvotes: 5

Views: 127

Answers (2)

Brad
Brad

Reputation: 4008

Yes there is. In Chapel, I/O is performed on channels. Each channel has an I/O style (represented by a record of type iostyle) which specifies how values are printed to that channel if a more specific style is not provided within the read/write call itself. A call to writeln() is essentially a call to stdout.writeln() where stdout is a channel whose output shows up in the console.

The following example shows how to change the I/O style of stdout (Try it Online):

// print to stdout using its default style                                                
writeln( 1.0 / 3.0 );

// create a new IO style with a precision of 15                                   
var style = new iostyle(precision=15);

// change stdout to use this new style                                          
stdout._set_style(style);

// print using the new style                                                    
writeln( 1.0 / 3.0 );

// restore the default style and print once more                                
stdout._set_style(defaultIOStyle());
writeln( 1.0 / 3.0 );

where the output is:

0.333333
0.333333333333333
0.333333

Note that it isn't safe to change the style of a channel in parallel code without locking it first. Since the example above is completely serial, it's OK, but in the context of a larger, potentially parallel, program, the better approach would be to lock the channel before setting its style, as follows (Try it Online):

// print to stdout using its default style                                                
writeln( 1.0 / 3.0 );

// create a new IO style with a precision of 15                                   
var style = new iostyle(precision=15);

// change stdout to use this new style                                          
stdout.lock();
stdout._set_style(style);
stdout.unlock();

// print using the new style                                                    
writeln( 1.0 / 3.0 );

// restore the default style and print once more                                
stdout.lock();
stdout._set_style(defaultIOStyle());
stdout.unlock();
writeln( 1.0 / 3.0 );

Chapel's online documentation has more information about I/O styles, the fields of the iostyle record, and locking of channels.

Upvotes: 5

Vass
Vass

Reputation: 431

Use iostyle and _set_style() :

writeln(100.0/3.0);   // 33.3333

stdout.lock();
stdout._set_style(new iostyle(precision=10));
stdout.unlock();

writeln(100.0/3.0);   // 33.33333333

You can also pass other things to new iostyle(), for example:

precision=10, realfmt=0          // like %.10g in C:  33.33333333      (default)
precision=10, realfmt=1          // like %.10f in C:  33.3333333333
precision=10, realfmt=2          // like %.10e in C:  3.3333333333e+01

Upvotes: 5

Related Questions